2017-11-29 14 views
2

使用thisスタックオーバーフローの問題次のコードがあります。フラット化[Any]配列スウィフト

let numbers = [1,[2,3]] as [Any] 
var flattened = numbers.flatMap { $0 } 
print(flattened) // [1, [2, 3]] 

代わりに、私はそれが[1, 2, 3]になりたい[1, [2, 3]]に設定されている平坦化。

Swiftでこれを達成する最も簡単できれいな方法は何ですか?

+0

'flatMap'は配列の配列で動作し、' Any'の配列では動作しません。 – rmaddy

+0

@rmaddyええ、私はそれを理解しました、それは今私にとって意味があります。私が欲しいものを達成するためにとにかくありますか?私が欲しいものを達成するのに役立つ「flatMap」の代替案がありますか? –

+0

おそらく解決策はここにあります:https://stackoverflow.com/questions/42587629/swift-function-taking-generic-array/42599849#42599849 –

答えて

2
extension Array { 
    var flattened: [Any] { 
     return flatMap { ($0 as? [Any])?.flattened ?? [$0] } 
    } 
    func flatMapped<T>(with type: T.Type? = nil) -> [T] { 
     guard let type = type else { 
      return flatMap { ($0 as? [Any])?.flatMapped() ?? ($0 as? T).map { [$0] } ?? [] } 
     } 
     return flatMap { ($0 as? [Any])?.flatMapped(with: type) ?? ($0 as? T).map { [$0] } ?? [] } 
    } 
} 

let objects: [Any] = [1,[2,3],"a",["b",["c","d"]]] 
let ftattened = objects.flattened // [1, 2, 3, "a", "b", "c", "d"] 

let integers = objects.flatMapped(with: Int.self) // [1, 2, 3] 
// setting the type explicitly 
let integers2: [Int] = objects.flatMapped()  // [1, 2, 3] 
// or casting 
let strings = objects.flatMapped() as [String]  // ["a", "b", "c", "d"] 
+0

私は文字列についても同じことができるでしょうか? –

+0

私はタイプをミックスしている(今は起こっていないが、将来の参照のために好奇心が強い)場合、どのように機能するだろうか? –

+1

配列を返すオーバーロードを使用している(つまり熱心に評価している)ので、 'lazy'はどちらの場合も冗長であることに注意してください。あなたは '($ 0はTですか?[$ 0は!T]:[])'を '($ Tは$ 0です).map {[$ 0]} ?? [] '個人的には私はおそらく'スイッチ 'を使用します(例えばhttps://gist.github.com/hamishknight/eca9b0be62056284ec37c3d49dd7db65)。また、個人的には、O(1)ではないので、メソッドを「平坦化」する方法があります。 – Hamish

4

あり、これを解決するためのより良い方法をすることが、1つの解決策は、Arrayに独自の拡張機能を記述することである可能性があります

extension Array { 
    func anyFlatten() -> [Any] { 
     var res = [Any]() 
     for val in self { 
      if let arr = val as? [Any] { 
       res.append(contentsOf: arr.anyFlatten()) 
      } else { 
       res.append(val) 
      } 
     } 

     return res 
    } 
} 

let numbers = [1,[2, [4, 5] ,3], "Hi"] as [Any] 
print(numbers.anyFlatten()) 

出力:

[ 1,2,4,5,3、 "Hi"]

このソリューションは、配列のネストを処理します。それは最も簡潔にそうように記述することができ

が、それは非常に不可解です:ここで

+1

これはflatMap式で実装できます: 'self.flatMap {($ 0 as?[Any])。map {$ 0.anyFlatten()} ?? [$ 0]} ' – Alexander

+0

@Alexanderそれはうまくいく、ありがとう。しかし、それは私のあまり「滑らかな」実装に比べて非常に非効率的です。 – rmaddy

+1

非効率性はどこですか? – Alexander

1

は@ rmaddyのanyFlattenの別の実装だ

extension Array { 
    func anyFlatten() -> [Any] { 
     return self.flatMap{ ($0 as? [Any]).map{ $0.anyFlatten() } ?? [$0] } 
    } 
} 

はここで、より合理的な実装です:

extension Array { 
    func anyFlatten() -> [Any] { 
     return self.flatMap{ element -> [Any] in 
      if let elementAsArray = element as? [Any] { return elementAsArray.anyFlatten() } 
      else { return [element] } 
     } 
    } 
} 
関連する問題