Skip to main content
Code Review

Return to Question

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

In Flatten to get all child controls of certain type in a UIView Flatten to get all child controls of certain type in a UIView, methods were discussed to recursively flatten a tree-like structure in Swift, resulting in an array of all elements.

In Flatten to get all child controls of certain type in a UIView, methods were discussed to recursively flatten a tree-like structure in Swift, resulting in an array of all elements.

In Flatten to get all child controls of certain type in a UIView, methods were discussed to recursively flatten a tree-like structure in Swift, resulting in an array of all elements.

Tweeted twitter.com/#!/StackCodeReview/status/588489978449133568
deleted 25 characters in body
Source Link
Martin R
  • 24.2k
  • 2
  • 38
  • 96
func sequentialFlatten<S : SequenceType>
 (seq : S, children : (S.Generator.Element) -> S) -> SequenceOf<S.Generator.Element>
{
 typealias E = S.Generator.Element
 return SequenceOf {
 () -> GeneratorOf<E>GeneratorOf<S.Generator.Element> in
 // Current generator, or `nil` if all sequences are exhausted:
 var gen : S.Generator? = seq.generate()
 // Queue of generators for sequences which still have to be enumerated:
 var queue : [S.Generator] = []
 return GeneratorOf {
 while gen != nil {
 if let next = gen!.next() {
 queue.append(children(next).generate())
 return next
 }
 // Current generator is empty, try to deque next one:
 gen = queue.first // `nil` if queue is empty
 if (gen != nil) {
 queue.removeAtIndex(0)
 }
 }
 return nil
 }
 }
}
  • Naming (function and variables).
  • Swifty-ness: things which should be done different in Swift.
  • Implementation: can the same be achieved easier, perhaps using available functions from the Swift standard library?
  • Can sequentialFlatten() be implemented in a way that it calls itself recursively?
func sequentialFlatten<S : SequenceType>
 (seq : S, children : (S.Generator.Element) -> S) -> SequenceOf<S.Generator.Element>
{
 typealias E = S.Generator.Element
 return SequenceOf {
 () -> GeneratorOf<E> in
 // Current generator, or `nil` if all sequences are exhausted:
 var gen : S.Generator? = seq.generate()
 // Queue of generators for sequences which still have to be enumerated:
 var queue : [S.Generator] = []
 return GeneratorOf {
 while gen != nil {
 if let next = gen!.next() {
 queue.append(children(next).generate())
 return next
 }
 // Current generator is empty, try to deque next one:
 gen = queue.first // `nil` if queue is empty
 if (gen != nil) {
 queue.removeAtIndex(0)
 }
 }
 return nil
 }
 }
}
  • Naming (function and variables).
  • Swifty-ness: things which should be done different in Swift.
  • Implementation: can the same be achieved easier, perhaps using available functions from the Swift standard library?
  • Can sequentialFlatten() implemented in a way that it calls itself recursively?
func sequentialFlatten<S : SequenceType>
 (seq : S, children : (S.Generator.Element) -> S) -> SequenceOf<S.Generator.Element>
{
 return SequenceOf {
 () -> GeneratorOf<S.Generator.Element> in
 // Current generator, or `nil` if all sequences are exhausted:
 var gen : S.Generator? = seq.generate()
 // Queue of generators for sequences which still have to be enumerated:
 var queue : [S.Generator] = []
 return GeneratorOf {
 while gen != nil {
 if let next = gen!.next() {
 queue.append(children(next).generate())
 return next
 }
 // Current generator is empty, try to deque next one:
 gen = queue.first // `nil` if queue is empty
 if (gen != nil) {
 queue.removeAtIndex(0)
 }
 }
 return nil
 }
 }
}
  • Naming (function and variables).
  • Swifty-ness: things which should be done different in Swift.
  • Implementation: can the same be achieved easier, perhaps using available functions from the Swift standard library?
  • Can sequentialFlatten() be implemented in a way that it calls itself recursively?
Source Link
Martin R
  • 24.2k
  • 2
  • 38
  • 96

Recursive flattening of Swift sequences

In Flatten to get all child controls of certain type in a UIView, methods were discussed to recursively flatten a tree-like structure in Swift, resulting in an array of all elements.

Motivated by that thread, I have written a flatten function which creates a sequence instead. This can be an advantage if the resulting elements are to be post-processed (e.g. filtered), because they can be created "lazily" or "on-demand", instead of creating an array with all resulting elements first.

func sequentialFlatten<S : SequenceType>
 (seq : S, children : (S.Generator.Element) -> S) -> SequenceOf<S.Generator.Element>
{
 typealias E = S.Generator.Element
 return SequenceOf {
 () -> GeneratorOf<E> in
 // Current generator, or `nil` if all sequences are exhausted:
 var gen : S.Generator? = seq.generate()
 // Queue of generators for sequences which still have to be enumerated:
 var queue : [S.Generator] = []
 return GeneratorOf {
 while gen != nil {
 if let next = gen!.next() {
 queue.append(children(next).generate())
 return next
 }
 // Current generator is empty, try to deque next one:
 gen = queue.first // `nil` if queue is empty
 if (gen != nil) {
 queue.removeAtIndex(0)
 }
 }
 return nil
 }
 }
}

The function arguments are an initial sequence, and a closure which transforms any sequence element into a new sequence (which may be empty). One can view seq as a set of root nodes in a tree or forest, and children as the mapping from each node to its children.

(Swift has a related flapMap() function which takes a sequence and a transformation as argument, but that does not work recursively, and returns an array and not a sequence.)

Example 1:

let someView : UIView = ...
let views = sequentialFlatten([someView], { 0ドル.subviews as! [UIView] })
let labels = lazy(views).filter( { 0ドル is UILabel } ).map( { 0ドル as! UILabel } )

creates a sequence of all views in the view hierarchy of someView, and then extracts all labels from that sequence. (Note that no intermediate array of all views is created.)

Example 2:

let seq = sequentialFlatten([0], { n in n < 50 ? [ 2*n+1, 2*n+2] : []})
for x in seq { println(x) }

is an unconventional method to print the numbers 0 ... 100.

I wrote this function mainly for my own educational purpose, to get more familiar with Swift sequences and generators. All feedback is welcome, for example:

  • Naming (function and variables).
  • Swifty-ness: things which should be done different in Swift.
  • Implementation: can the same be achieved easier, perhaps using available functions from the Swift standard library?
  • Can sequentialFlatten() implemented in a way that it calls itself recursively?
default

AltStyle によって変換されたページ (->オリジナル) /