2017-11-29 3 views
2

사용 this 스택 오버플로 질문 다음 코드가 있습니다.Flatten [Any] Array Swift

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

대신이 나는 그것이 [1, 2, 3]되고 싶어 [1, [2, 3]]로 설정되고 평평.

스위프트에서 가장 쉽고/깨끗한 방법은 무엇입니까?

+0

:

여기
extension Array { func anyFlatten() -> [Any] { return self.flatMap{ ($0 as? [Any]).map{ $0.anyFlatten() } ?? [$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는인가? ($!는 T) : [])'를'($ T는 $ 0) .map {[$ 0]}로 바꿀 수 있습니다. ?? []'개인적으로는 아마도 '스위치'를 사용할 것입니다 (예 : https://gist.github.com/hamishknight/eca9b0be62056284ec37c3d49dd7db65). 또한, 나는 개인적으로 O (1)가 아닌'flattened '메소드를 만들 것입니다. – Hamish

4

이이 문제를 해결하기 위해 더 나은 방법 일 수 있지만, 하나 개의 솔루션은 어레이에 자신의 확장을 작성하는 것입니다 수 있습니다

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{ element -> [Any] in 
      if let elementAsArray = element as? [Any] { return elementAsArray.anyFlatten() } 
      else { return [element] } 
     } 
    } 
}