Swift'te Diziler Dizisini Düzleştir


145

Swift'te flattenScala, Xtend, Groovy, Ruby ve co'da bir muadili var mı ?

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

Tabii ki azaltmak için kullanabilirsiniz ama bu berbat

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

dizi eklemek nesnesi kullanmak gibi değil mi?
Pham Hoan

Henüz Swift'in kendisine bakmadım ama Haskell ve F # 'da `` concat' '- belki böyle bir şeye bakabilirsin? - Bunun bir yerde olduğunu çok olumlu görüyorum (çoğu FP dili. Monad'ları biliyor ve bu List'in bağlantısı)
Carsten

evet haskell'de buna aslında concat denir.
Christian Dietrich


Yanıtlar:


437

Swift> = 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())

resim açıklamasını buraya girin


3
Sadece daha genel flatMapolarak ifade etmek gerekirse, Swift 1.2'den itibaren mevcuttur.
Mick MacCallum

3
joined(resmi olarak bilinir flatten) ile arasındaki fark flatMapnedir? Ederken o kadar mı flatMapkatılır, aynı zamanda / map şeyleri dönüştürebilir. ama burada örnekte gerçekten ihtiyacımız yok yani geri $0
Honey

6
@Dschee flatMapolacak ya da bir 1 D dizisi bir 2D dizi dümdüz veya kaldırma nilikisi, değerler. 1. düzey dizinin Elementbir dizi veya isteğe bağlı olup olmadığına bağlı olarak hangisinin yapılacağını belirler. Bu nedenle, 2B bir dizi dizi seçenek (örneğin [[Int?]]) geçirirseniz, bunu 1D (örneğin [Int?]) düzleştirmeyi seçer . Hem 1-B'ye düzleştirmek hem de 2. seviye sıfırları kaldırmak için yapmanız gerekir array.flatMap { $0 }.flatMap { $0 }. Başka bir deyişle, boyut düzleştirme eşittir Array(array.joined())ve sıfır kaldırma “düzleştirme” eşittir array.filter{ $0 != nil }.map{ $0! }.
Slipp D.Thompson

1
@Warpling flatMap, soruda açıklanan kullanım için hala uygundur (bir 2D diziyi 1D'ye düzleştirmek). compactMap, nilbir flatMapkerede yapılan bir varyasyon olarak bir diziden öğeleri kaldırmak içindir .
Jim Dovey

1
@mohamadrezakoohkan doğru. Diziniz tür olduğundan [[Any]], flatMapbasitçe onu [Any]([1, 2, 3, 4, [5, 6], 7, 8, 9]) türüne dönüştürür . Ve flatMaptekrar başvurursak , `` Herhangi? Burada, derleyicinin basit bir değer mi yoksa dizinin kendisi mi olduğunu artık bilmemesi.
andreschneider

31

Swift standart kütüphanesinde olduğu joineduygun her türlü uygulamaya fonksiyonu Sequence(veya protokol flattenile SequenceTypeiçerir, Swift 3 öncesi) Array:

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

Bazı durumlarda joined(), yeni bir dizi yerine tembel bir koleksiyon döndürdüğü için kullanımı yararlı olabilir, ancak Array()yukarıdaki örnekte olduğu gibi başlatıcıya geçirildiğinde her zaman bir diziye dönüştürülebilir .


@chrisco, cevabımın nasıl yanlış olduğunu ve "en basit doğru cevap" için hangi kriterleri inceleyebilir misiniz? Bir yanıtı silmenin soruyu herhangi bir şekilde nasıl etkileyebileceğini de söyleyebilir misiniz?
Max Desiatov

Önce snippet'inizi çalıştırmayı deneyin - sizce ne işe yarıyor? Aslında ne yapar? Asıl soru neydi? Cevabınız doğru mu? Değilse, bu yayının netliğini artırmak için silmek daha iyi olur. Aynı şeyi yanlış cevaplarımla yaptım.
Chris Conover

1
@chrisco önerileriniz için çok teşekkür ederim, ancak snippet'leri herhangi bir yere göndermeden önce çalıştırıyorum. Ve cevabım doğru, OP'nin talep ettiği sonuçların aynısını döndürdüğü ve bunun için daha az kod kullandığı için doğru. Soruda herhangi bir kısıtlama olmamasına rağmen, orijinal cevabımın bir dizi yerine tembel koleksiyon döndürdüğünü itiraf ediyorum. Hala doğru cevabı silmenin sorunun kalitesini hiçbir şekilde artırdığını düşünmüyorum.
Max Desiatov

Bu benim noktası oldu - test ederken / çıkış baskı, sen diziler içeren bir dizi almak: FlattenBidirectionalCollection<Array<Array<Int>>>(_base: [[1, 2, 3], [4], [5, 6, 7, 8, 9]])). Noktanız buna rağmen düz bir dizi gibi erişebildiğiniz için geçerlidir, bu yüzden CustomStringConvertableuygulamanın yanıltıcı olduğu görülmektedir. Kod snippet'iniz yine de bir testten geçti ve hala eksik.
Chris Conover

1
Hızlı 3.0 itibariyle, flatten()yeniden adlandırıldıjoined()
Bay Xcoder

16

Hızlı 4.x / 5.x

Dizide biraz daha karmaşıklık eklemek için, dizileri içeren bir dizi varsa, o flatMapzaman gerçekten başarısız olur.

Dizinin

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

Ne flatMapya compactMapgetirileridir:

array.compactMap({$0})

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

Bu sorunu çözmek için, basit döngü mantığı + özyineleme

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
}

Bu nedenle verilen dizi ile bu işlevi çağırın

flattenedArray(array: array)

Sonuç:

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

Bu fonksiyon örneği değerlendirildiğinde, dizinin her türlü düzleştirmek için yardımcı olacaktır Intburada

Oyun Alanı Çıkışı: resim açıklamasını buraya girin




2

Hızlı 4.2

Aşağıda basit bir dizi uzantısı yazdım. Başka bir dizi veya öğe içeren bir diziyi düzleştirmek için kullanabilirsiniz. join () yönteminin aksine.

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)
    }
}

kullanımı:

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

numbers.flatten()

1

Bir başka daha genel uygulama reduce,

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

Bu aynı şeyi başarır, ama içinde olup bitenler hakkında daha fazla bilgi verebilir reduce.

Apple'ın belgelerinden,

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

Açıklama

Tekrar tekrar arama sonucu Dönüş kombine başlatılır birikmiş değeri ile başlangıç ve her bir elemanınSırayla dizi döndürün.


Use of unresolved identifier 'reduce'
Jason Moore

1

@ RahmiBozdağ'ın cevabı değiştirildi, 1. Genel uzantılardaki yöntemler herkese açık. 2. Başlangıç ​​dizini her zaman sıfır olacağından fazladan yöntem kaldırıldı. 3. Nil ve opsiyonel için compactMap'i içine koymanın bir yolunu bulamadım çünkü T metodunun içinde her zaman [Herhangi?], Herhangi bir öneri bekliyoruz.

 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

Yuvalanmış diziyi aşağıdaki yöntemi kullanarak düzleştirebilirsiniz:

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 sürüm 5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9)
Hedef: x86_64-apple-darwin19.2.0

Ekran görüntüsü

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

Swift 5.1

public extension Array where Element: Collection {

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

Sözlük değerleri için de isterseniz:

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


-1

matris [[myDTO]]?

Hızlı 5'te bunu kullanabilirsiniz = Dizi (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)
}

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.