Array#flatten
以下のような実装をしてみました。
extension Array {
func flatten() -> [AnyObject] {
var flattenArray = [AnyObject]()
for element in self {
if let element = element as? NSArray as? [AnyObject] {
flattenArray += element.flatten()
} else {
flattenArray.append(element as NSObject)
}
}
return flattenArray
}
}
var temp = [1, [2, 3, 4, [5, 6]]]
var flat = temp.flatten()
println(flat) // [1, 2, 3, 4, 5, 6]
実装について補足
if let element = element as NSArray as? [AnyObject] {}
という処理について少し補足します。
まず、なんでNSArray
にキャストしてからArray<AnyObject>
にキャストしているんだ?
と疑問に思われるかもしれませんが、
これはT
型(placeholder type)のelement
を直接Array<AnyObject>
へキャストしようとすると、element
の実際の型がArray<AnyObject>
だったとしてもnil
になるためです。
if let element = element as? [AnyObject] {}
とした場合、この挙動は以下のような期待していない結果を招きます。
var temp:[Any] = [[1, [2, 3, 4, [5, 6]]]]
var flat = temp.flatten()
println(flat) // [(1,(2,3,4,(5,6)))]
つまりelement
をArray<AnyObject>
にキャストすることに失敗し、再帰的に平坦化できなくなっていまっている、ということです。
解決策
そこで、Working with Cocoa Data Typesで説明されている、
「要素の型がクラスのインスタンスでないArray
をNSArray
にキャストしたときに、Swiftは暗黙的に要素の型もAnyObject
互換な型にキャストする」
let schoolSupplies: NSArray = ["Pencil", "Eraser", "Notebook"]
// schoolSupplies is an NSArray object containing NSString objects
という性質を利用して、element
を間接的にArray<AnyObjec>
にキャストしています。