แผ่อาร์เรย์ของอาร์เรย์ใน Swift


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
}

ไม่ชอบใช้เพิ่มวัตถุของอาร์เรย์หรือไม่
Pham Hoan

ฉันยังไม่ได้ดู Swift แต่ใน Haskell และ F # เป็น `concat '- ดังนั้นอาจจะมีบางอย่างที่มีชื่อเช่นนี้? - ฉันค่อนข้างแน่ใจว่านี่มีอยู่ที่ไหนซักแห่ง (ส่วนใหญ่ FP. รู้เกี่ยวกับพระและนี่คือ List's bind)
Carsten

ใช่ใน Haskell มันถูกเรียกว่า concat
Christian Dietrich

คุณควรจะยอมรับคำตอบของ andreschneider
Rob

คำตอบ:


436

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

ป้อนคำอธิบายรูปภาพที่นี่


3
เพียงระบุสถานะนี้โดยทั่วไปflatMapจะมีให้ตั้งแต่ Swift 1.2
มิก MacCallum

3
อะไรคือความแตกต่างระหว่างjoined(หรือที่รู้จักกันอย่างเป็นทางการflatten) กับflatMap? ในขณะที่flatMapเข้าร่วมก็สามารถแมป / แปลงสิ่งต่าง ๆ ได้ แต่ที่นี่ในตัวอย่างที่เราไม่ต้องการจริงๆนั่นคือเรากลับมา$0
ฮันนี่

6
@Dschee flatMapจะทำให้ทั้งสองอาร์เรย์แบนลงในอาร์เรย์ 1D หรือลบnilค่าไม่ใช่ทั้งสองอย่าง มันเป็นตัวกำหนดที่จะทำบนพื้นฐานถ้าอาร์เรย์ที่ 1 ระดับของElementเป็นอาร์เรย์หรือ optional- ดังนั้นหากคุณผ่านมันอาร์เรย์ 2 มิติของ optionals (เช่น[[Int?]])ก็จะเลือกที่จะแผ่ไปยัง 1D (เช่น[Int?] ) ให้เรียบทั้ง 1-D และลบ 2 ระดับ Nils array.flatMap { $0 }.flatMap { $0 }คุณจะต้องทำ กล่าวอีกนัยหนึ่งขนาดแฟลตติ้งเท่ากับArray(array.joined())และจะไม่มี“ แฟลตติ้ง” เท่ากับarray.filter{ $0 != nil }.map{ $0! }ลบ
Slipp D. Thompson

1
@ การสุ่มตัวอย่างflatMapยังคงเหมาะสมสำหรับการใช้งานที่อธิบายไว้ในคำถาม (การทำให้อาร์เรย์ 2 มิติแบนราบเป็น 1D) compactMapชัดเจนสำหรับการลบnilรายการออกจากลำดับซึ่งแตกต่างจากflatMapครั้งหนึ่งเคยเป็น
Jim Dovey

1
@mohamadrezakoohkan ที่ถูกต้อง เนื่องจากอาเรย์ของคุณเป็นประเภท[[Any]]ดังนั้นflatMapเพียงแปลงเป็นประเภท[Any]([1, 2, 3, 4, [5, 6], 7, 8, 9] และถ้าเราจะสมัครflatMapอีกครั้งเราจะทำอะไรกับ `อะไร? ประเภทที่คอมไพเลอร์ไม่ทราบอีกต่อไปว่ามันเป็นค่าง่ายหรืออาร์เรย์เอง
andreschneider

31

ในห้องสมุดมาตรฐาน Swift มีjoinedฟังก์ชั่นการใช้งานสำหรับทุกประเภทที่สอดคล้องกับSequenceโปรโตคอล (หรือflattenเปิดSequenceTypeก่อน Swift 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
ในฐานะของ swift 3.0 flatten()ได้ถูกเปลี่ยนชื่อเป็นjoined()
Mr. Xcoder

16

Swift 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]

เพื่อแก้ปัญหานี้เราสามารถใช้การวนรอบแบบลอจิก + การเรียกซ้ำแบบง่าย ๆ ของเรา

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

ฉันเขียนส่วนขยายอาร์เรย์แบบง่ายด้านล่าง คุณสามารถใช้เพื่อทำให้เรียบอาร์เรย์ที่มีอาร์เรย์หรือองค์ประกอบอื่น ซึ่งแตกต่างจากวิธีการเข้าร่วม ()

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ขึ้น

จากเอกสารของ Apple

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

ลักษณะ

กลับผลจากการซ้ำ ๆ เรียกรวมมีมูลค่าสะสมเริ่มต้นที่จะเริ่มต้นและองค์ประกอบของแต่ละลำดับในทางกลับกัน


ฉันได้รับรหัสของคุณ:Use of unresolved identifier 'reduce'
Jason Moore

1

Modified @ RahmiBozdag คำตอบของ 1. วิธีการในส่วนขยายสาธารณะเป็นสาธารณะ 2. ลบวิธีพิเศษเนื่องจากดัชนีเริ่มต้นจะเป็นศูนย์เสมอ 3. ฉันไม่พบวิธีที่จะวาง compactMap ไว้ภายในสำหรับศูนย์และตัวเลือกได้เนื่องจากวิธีการภายใน T อยู่เสมอ [มี?] คำแนะนำใด ๆ จะได้รับการต้อนรับ

 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([], +)
    }
}



-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.