I'm starting to learn about closures and want to implement them in a project I'm working on and I'd like some help.
I have a class defined as follows:
class MyObject {
var name: String?
var type: String?
var subObjects: [MyObject]?
}
And I want to use closures or higher oder functions (something like flatMap
comes to mind) to flatten an [MyObject]
and joining all MyObject
and subOjects
into one array.
I've tried using [MyObject].flatMap()
but this operation doesn't return the nested subObjects.
One approach to flattening a recursive class structure is with a recursive function.
Here is the class that we would like flattened:
public class Nested {
public let n : Int
public let sub : [Nested]?
public init(_ n:Int, _ sub:[Nested]?) {
self.n = n
self.sub = sub
}
}
Here is the function that demonstrates how this could be done:
func test() {
let h = [
Nested(1, [Nested(2, nil), Nested(3, nil)])
, Nested(4, nil)
, Nested(5, [Nested(6, nil), Nested(7, [Nested(8, nil), Nested(9, nil)])])
]
func recursiveFlat(next:Nested) -> [Nested] {
var res = [Nested]()
res.append(next)
if let subArray = next.sub {
res.appendContentsOf(subArray.flatMap({ (item) -> [Nested] in
recursiveFlat(item)
}))
}
return res
}
for item in h.flatMap(recursiveFlat) {
print(item.n)
}
}
The heart of this approach is recursiveFlat
local function. It appends the content of the nested object to the result, and then conditionally calls itself for each element to add their contents as well.
First, I would highly recommend making the type of subObjects
be non-optional. There's rarely a reason for optional arrays. Do you really need to distinguish between "no array" and "an empty array?" This is very uncommon. If you make subObjects
just be an array, you can write what you're describing as a simple recursive function:
func flattenMyObjects(myObjects: [MyObject]) -> [MyObject] {
return myObjects.flatMap { (myObject) -> [MyObject] in
var result = [myObject]
result.appendContentsOf(flattenMyObjects(myObject.subObjects))
return result
}
}
If you need it to be optional, the changes are minor (you'll need to add an if-let or something similar).