스위프트에서 배열의 배열을 평평하게


144

Swift flatten에는 Scala, Xtend, Groovy, Ruby 및 co에 대응하는 것이 있습니까?

var aofa = [[1,2,3],[4],[5,6,7,8,9]]
aofa.flatten() // shall deliver [1,2,3,4,5,6,7,8,9] 

물론 나는 그것을 줄이기 위해 사용할 수 있지만 그 짜증

var flattened = aofa.reduce(Int[]()){
    a,i in var b : Int[] = a
    b.extend(i)
    return b
}

배열의 add 객체를 사용하는 것과 같지 않습니까?
Pham Hoan

Swift 자체는 아직 보지 않았지만 Haskell과 F #에서는`concat`입니다. 그래서 이런 식으로 보일까요? -나는 이것이 아마도 어딘가에 있다고 긍정적입니다 (대부분의 FP 랭귀지. 모나드에 대해 알고 이것이리스트의 바인딩입니다)
Carsten

네, haskell에서는 실제로 concat이라고합니다.
Christian Dietrich

andreschneider 's answer을 수락해야합니다 .
Rob

답변:


436

스위프트> = 3.0

reduce:

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let reduced = numbers.reduce([], +)

flatMap:

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let flattened = numbers.flatMap { $0 }

joined:

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let joined = Array(numbers.joined())

여기에 이미지 설명을 입력하십시오


3
이것을 좀 더 일반적으로 flatMap말하면 Swift 1.2부터 사용할 수 있습니다.
Mick MacCallum

3
joined(공식적으로 알려진 flatten) 의 차이점은 무엇 flatMap입니까? flatMap조인 하는 동안 사물을 매핑 / 변환 할 수도 있습니다. 그러나 여기 예제에서 우리는 정말로 필요하지 않습니다. 즉 우리는 돌아옵니다$0
Honey

6
@Dschee는 flatMap 1 차원 어레이로 2 차원 배열을 평탄화 하거나 제거 nil하지 모두 값. 그것은 1 수준의 배열의가 경우에 따라 할 수있는 결정 Element당신이 그것을 선택적 항목의 2 차원 배열 전달하면 배열이나 optional- 이렇게이다 (예를 [[Int?]]) 은 1D에 평평하게 선택할 수 있습니다 (예를 들어 [Int?]) . 1 차원으로 평면화하고 2 단계 nil을 제거하려면을 수행해야 array.flatMap { $0 }.flatMap { $0 }합니다. 다시 말하면, 치수 평탄화는 동일 Array(array.joined())하고 무-제거 "평면화"는 동일하다 array.filter{ $0 != nil }.map{ $0! }.
슬립 D. 톰슨

1
@Warpling flatMap은 여전히 ​​문제에 설명 된 용도에 적합합니다 (2D 배열을 1D로 평면화). 한 번의 변형처럼 시퀀스에서 항목을 compactMap명시 적으로 제거하기위한 것 입니다. nilflatMap
Jim Dovey

1
@mohamadrezakoohkan 맞습니다. 배열이 유형 [[Any]]이므로 flatMap간단히 배열 을 [Any]([1, 2, 3, 4, [5, 6], 7, 8, 9]) 유형으로 변환합니다. 그리고 우리가 flatMap다시 지원한다면 , 우리는`Any? 컴파일러는 단순한 값이거나 배열 자체인지 더 이상 알 수없는 형식입니다.
andreschneider

31

신속한 표준 라이브러리가 joined따르는 모든 유형의 구현 기능 Sequence(또는 프로토콜 flattenSequenceType포함하기 전에 신속한 3) Array:

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let flattened = Array(numbers.joined())

경우에 따라 사용 joined()하면 새 배열 대신 게으른 컬렉션을 반환하므로 유용 할 수 있지만 Array()위 예제와 같이 이니셜 라이저로 전달 될 때 항상 배열로 변환 할 수 있습니다 .


@ chrisco 내 답변이 어떻게 틀렸는 지, "가장 간단한 답변"에 대한 기준은 무엇입니까? 답변을 삭제하면 어떤 식 으로든 질문에 영향을 줄 수있는 방법을 알려주시겠습니까?
Max Desiatov

스 니펫을 먼저 실행 해보십시오. 어떻게 생각하십니까? 실제로 무엇을합니까? 원래 질문은 무엇입니까? 답이 맞습니까? 그렇지 않은 경우이 게시물의 명확성을 높이기 위해 삭제하는 것이 좋습니다. 나는 내 자신의 잘못된 답변으로 똑같이했습니다.
Chris Conover

1
@ chrisco는 귀하의 제안에 대해 대단히 감사하지만 어디서나 게시하기 전에 스 니펫을 실행합니다. 그리고 내 대답은 OP 요청과 정확히 동일한 결과를 반환하고 더 적은 코드를 사용하기 때문에 정확합니다. 나는 원래의 대답이 배열 대신 게으른 컬렉션을 반환하고 있음을 인정하지만 질문에는 제한이 없었습니다. 나는 여전히 정답을 삭제해도 어떤 식 으로든 질문의 질이 향상된다고 생각하지 않습니다.
Max Desiatov

이것은 내 요점-출력을 테스트 / 인쇄 할 때 배열 배열을 얻는다는 것 FlattenBidirectionalCollection<Array<Array<Int>>>(_base: [[1, 2, 3], [4], [5, 6, 7, 8, 9]]))입니다. 포인트는 평면 배열처럼 액세스 할 수 있지만 유효하므로 CustomStringConvertable구현이 잘못되어있는 것 같습니다 . 코드 스 니펫은 여전히 ​​테스트가 누락되었습니다.
Chris Conover

1
스위프트 3.0 기준 flatten()으로 이름이 변경되었습니다joined()
Mr. Xcoder

16

스위프트 4.x / 5.x

배열에 약간의 복잡성을 추가하기 위해 배열 배열을 포함하는 배열이 있으면 flatMap실제로 실패합니다.

배열이

var array:[Any] = [1,2,[[3,4],[5,6,[7]]],8]

어떤 flatMap또는 compactMap반환하는 것입니다 :

array.compactMap({$0})

//Output
[1, 2, [[3, 4], [5, 6, [7]]], 8]

이 문제를 해결하기 위해 간단한 for 루프 논리 + 재귀를 사용할 수 있습니다.

func flattenedArray(array:[Any]) -> [Int] {
    var myArray = [Int]()
    for element in array {
        if let element = element as? Int {
            myArray.append(element)
        }
        if let element = element as? [Any] {
            let result = flattenedArray(array: element)
            for i in result {
                myArray.append(i)
            }

        }
    }
    return myArray
}

주어진 배열 로이 함수를 호출하십시오.

flattenedArray(array: array)

결과는 다음과 같습니다

[1, 2, 3, 4, 5, 6, 7, 8]

이 기능은 Int여기 의 경우를 고려하여 모든 종류의 배열을 평평하게하는 데 도움이 됩니다

운동장 출력 : 여기에 이미지 설명을 입력하십시오




2

스위프트 4.2

아래에 간단한 배열 확장을 썼습니다. 다른 배열 또는 요소가 포함 된 배열을 병합하는 데 사용할 수 있습니다. joined () 메소드와는 다릅니다.

public extension Array {
    public func flatten() -> [Element] {
        return Array.flatten(0, self)
    }

    public static func flatten<Element>(_ index: Int, _ toFlat: [Element]) -> [Element] {
        guard index < toFlat.count else { return [] }

        var flatten: [Element] = []

        if let itemArr = toFlat[index] as? [Element] {
            flatten = flatten + itemArr.flatten()
        } else {
            flatten.append(toFlat[index])
        }

        return flatten + Array.flatten(index + 1, toFlat)
    }
}

용법:

let numbers: [Any] = [1, [2, "3"], 4, ["5", 6, 7], "8", [9, 10]]

numbers.flatten()

1

또 다른 더 일반적인 구현 reduce,

let numbers = [[1,2,3],[4],[5,6,7,8,9]]
let reduced = reduce(numbers,[],+)

이것은 같은 일을 수행하는데 무슨 일이 일어나고 있는지 더 많은 통찰력을 줄 수 있습니다 reduce.

애플의 문서에서

func reduce<S : SequenceType, U>(sequence: S, initial: U, combine: (U, S.Generator.Element) -> U) -> U

기술

이니셜시퀀스의 각 요소로 초기화 된 누적 값을 사용하여 반복적으로 결합 호출의 결과를 반환합니다 .


귀하의 코드와 함께 얻을 수 있습니다 :Use of unresolved identifier 'reduce'
Jason Moore

1

@RahmiBozdag의 답변을 수정했습니다. 1. 공개 확장의 메소드는 공개입니다. 2. 시작 색인이 항상 0이므로 추가 방법을 제거했습니다. 3. 내부 메서드 T가 항상 [Any?]이므로 compactMap을 nil 및 옵션에 넣을 수있는 방법을 찾지 못했습니다. 어떤 제안도 환영합니다.

 let array = [[[1, 2, 3], 4], 5, [6, [9], 10], 11, nil] as [Any?]

 public extension Array {

 func flatten<T>(_ index: Int = 0) -> [T] {
        guard index < self.count else { 
            return [] 
        }

        var flatten: [T] = []

        if let itemArr = self[index] as? [T] {
            flatten += itemArr.flatten()
        } else if let element = self[index] as? T {
            flatten.append(element)
        }
        return flatten + self.flatten(index + 1)
   }

}

let result: [Any] = array.flatten().compactMap { $0 }
print(result)
//[1, 2, 3, 4, 5, 6, 9, 10, 11]

0

다음 방법을 사용하여 중첩 배열을 병합 할 수 있습니다.

var arrays = [1, 2, 3, 4, 5, [12, 22, 32], [[1, 2, 3], 1, 3, 4, [[[777, 888, 8999]]]]] as [Any]

func flatten(_ array: [Any]) -> [Any] {

    return array.reduce([Any]()) { result, current in
        switch current {
        case(let arrayOfAny as [Any]):
            return result + flatten(arrayOfAny)
        default:
            return result + [current]
        }
    }
}

let result = flatten(arrays)

print(result)

/// [1, 2, 3, 4, 5, 12, 22, 32, 1, 2, 3, 1, 3, 4, 777, 888, 8999]

0

Apple Swift 버전 5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9)
대상 : x86_64-apple-darwin19.2.0

스크린 샷

let optionalNumbers = [[1, 2, 3, nil], nil, [4], [5, 6, 7, 8, 9]]
print(optionalNumbers.compactMap { $0 }) // [[Optional(1), Optional(2), Optional(3), nil], [Optional(4)], [Optional(5), Optional(6), Optional(7), Optional(8), Optional(9)]]
print(optionalNumbers.compactMap { $0 }.reduce([], +).map { $0 as? Int ?? nil }.compactMap{ $0 }) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(optionalNumbers.compactMap { $0 }.flatMap { $0 }.map { $0 as? Int ?? nil }.compactMap{ $0 }) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(Array(optionalNumbers.compactMap { $0 }.joined()).map { $0 as? Int ?? nil }.compactMap{ $0 }) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

let nonOptionalNumbers = [[1, 2, 3], [4], [5, 6, 7, 8, 9]]
print(nonOptionalNumbers.compactMap { $0 }) // [[1, 2, 3], [4], [5, 6, 7, 8, 9]]
print(nonOptionalNumbers.reduce([], +)) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(nonOptionalNumbers.flatMap { $0 }) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(Array(nonOptionalNumbers.joined())) // [1, 2, 3, 4, 5, 6, 7, 8, 9]

0

스위프트 5.1

public extension Array where Element: Collection {

    func flatten() -> [Element.Element] {
        return reduce([], +)
    }
}

사전 값에 대해 원하는 경우 :

public extension Dictionary.Values where Value : Collection {
    func flatten() -> [Value.Element]{
         return self.reduce([], +)
    }
}


-1

행렬은 [[myDTO]]입니까?

신속한 5에서는 this = Array (self.matrix! .joined ())를 사용할 수 있습니다


-2
func convert(){
    let arr = [[1,2,3],[4],[5,6,7,8,9]]
    print("Old Arr = ",arr)
    var newArr = [Int]()
    for i in arr{
        for j in i{
            newArr.append(j)
        }
    }
    print("New Arr = ",newArr)
}

여기에 이미지 설명을 입력하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.