【问题标题】:How do I concatenate or merge arrays in Swift?如何在 Swift 中连接或合并数组?
【发布时间】:2014-09-28 13:29:16
【问题描述】:

如果有两个像这样在 swift 中创建的数组:

var a:[CGFloat] = [1, 2, 3]
var b:[CGFloat] = [4, 5, 6]

如何将它们合并到[1, 2, 3, 4, 5, 6]

【问题讨论】:

标签: arrays swift merge


【解决方案1】:

您可以将数组与+ 连接,构建一个新数组

let c = a + b
print(c) // [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]

或使用+=(或append)将一个数组附加到另​​一个数组:

a += b

// Or:
a.append(contentsOf: b)  // Swift 3
a.appendContentsOf(b)    // Swift 2
a.extend(b)              // Swift 1.2

print(a) // [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]

【讨论】:

  • [AnyObect]?与 CGFloat 不同。在连接到 AnyObject 数组时。
  • Khunshan:AnyObject 表示一个对象,据我了解,这意味着从类类型实例化的东西。 CGFloat 不是一个对象,它是一个标量值。据我了解,数组可以包含标量,除非它被定义为包含AnyObject 或进一步细化。但是,我怀疑这里的问题是数组被包裹在一个可选中,所以你必须先用!? 解开它。
  • 我们是否知道 Swift 2 的 Copy-On-Write 智能是否扩展到确定 ab 部分是否被修改(因此可能在 a.appendContentsOf(b) 期间省略了 b 的副本) ?
  • @OwenGodfrey 谢谢。我对 appendContentsOf 和 insertContentsOf 有点困惑。
【解决方案2】:

在 Swift 5 中,根据您的需要,您可以选择以下六种方式中的一种来连接/合并两个数组。


#1。使用Array+(_:_:)泛型运算符将两个数组合并成一个新数组

Array 有一个+(_:_:) 通用运算符。 +(_:_:) 有以下declaration

通过连接集合和序列的元素来创建一个新集合。

static func + <Other>(lhs: Array<Element>, rhs: Other) -> Array<Element> where Other : Sequence, Self.Element == Other.Element

以下 Playground 示例代码展示了如何使用 +(_:_:) 泛型运算符将两个 [Int] 类型的数组合并为一个新数组:

let array1 = [1, 2, 3]
let array2 = [4, 5, 6]

let flattenArray = array1 + array2
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]

#2。使用Array+=(_:_:) 泛型运算符将数组的元素附加到现有数组中

Array 有一个+=(_:_:) 通用运算符。 +=(_:_:) 有以下declaration

将序列的元素附加到范围可替换的集合中。

static func += <Other>(lhs: inout Array<Element>, rhs: Other) where Other : Sequence, Self.Element == Other.Element

以下 Playground 示例代码展示了如何使用 +=(_:_:) 泛型运算符将 [Int] 类型数组的元素附加到现有数组中:

var array1 = [1, 2, 3]
let array2 = [4, 5, 6]

array1 += array2
print(array1) // prints [1, 2, 3, 4, 5, 6]

#3。使用Arrayappend(contentsOf:) 方法将一个数组追加到另一个数组

Swift Array 有一个 append(contentsOf:) 方法。 append(contentsOf:) 有以下declaration

将序列或集合的元素添加到此集合的末尾。

mutating func append<S>(contentsOf newElements: S) where S : Sequence, Self.Element == S.Element

以下 Playground 示例代码展示了如何使用 append(contentsOf:) 方法将一个数组附加到另​​一个类型为 [Int] 的数组:

var array1 = [1, 2, 3]
let array2 = [4, 5, 6]

array1.append(contentsOf: array2)
print(array1) // prints [1, 2, 3, 4, 5, 6]

#4。使用SequenceflatMap(_:)方法将两个数组合并成一个新数组

Swift 为所有符合Sequence 协议的类型(包括Array)提供了一个flatMap(_:) 方法。 flatMap(_:) 有以下declaration

返回一个数组,其中包含使用此序列的每个元素调用给定转换的连接结果。

func flatMap<SegmentOfResult>(_ transform: (Self.Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence

以下 Playground 示例代码展示了如何使用 flatMap(_:) 方法将两个 [Int] 类型的数组合并为一个新数组:

let array1 = [1, 2, 3]
let array2 = [4, 5, 6]

let flattenArray = [array1, array2].flatMap({ (element: [Int]) -> [Int] in
    return element
})
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]

#5。使用Sequencejoined()方法和Arrayinit(_:)初始化器将两个数组合并成一个新数组

Swift 为所有符合Sequence 协议的类型(包括Array)提供了一个joined() 方法。 joined() 有以下declaration

返回此序列序列的元素,串联。

func joined() -> FlattenSequence<Self>

此外,Swift Array 有一个 init(_:) 初始化器。 init(_:) 有以下declaration

创建一个包含序列元素的数组。

init<S>(_ s: S) where Element == S.Element, S : Sequence

因此,以下 Playground 示例代码展示了如何使用 joined() 方法和 init(_:) 初始化器将两个 [Int] 类型的数组合并为一个新数组:

let array1 = [1, 2, 3]
let array2 = [4, 5, 6]

let flattenCollection = [array1, array2].joined() // type: FlattenBidirectionalCollection<[Array<Int>]>
let flattenArray = Array(flattenCollection)
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]

#6。使用Arrayreduce(_:_:)方法将两个数组合并成一个新数组

Swift Array 有一个 reduce(_:_:) 方法。 reduce(_:_:) 有以下declaration

返回使用给定闭包组合序列元素的结果。

func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

以下 Playground 代码展示了如何使用 reduce(_:_:) 方法将两个 [Int] 类型的数组合并为一个新数组:

let array1 = [1, 2, 3]
let array2 = [4, 5, 6]

let flattenArray = [array1, array2].reduce([], { (result: [Int], element: [Int]) -> [Int] in
    return result + element
})
print(flattenArray) // prints [1, 2, 3, 4, 5, 6]

【讨论】:

  • 感谢分享此代码,很好的解释,只是对您的回答的补充,最好,如果您说哪个性能更有效?
  • 我喜欢 + 用于 2 个数组,joined() 用于数组数组。
  • 如果您要合并超过 2 个数组(或字符串或其他任何内容),请克制自己不要使用 + 运算符,它会产生绝对疯狂的编译时间。
  • @lawicko 你会推荐哪种方法?
  • @Cyber​​Mew 任何不使用重载运算符的东西,我喜欢方法#3,因为我认为它最易读,但我也喜欢方法#4 与平面地图。对于字符串,我喜欢方法#5,因为最后你会立即得到连接的字符串。
【解决方案3】:

如果您不是运算符重载的忠实粉丝,或者只是更喜欢函数类型:

// use flatMap
let result = [
    ["merge", "me"], 
    ["We", "shall", "unite"],
    ["magic"]
].flatMap { $0 }
// Output: ["merge", "me", "We", "shall", "unite", "magic"]

// ... or reduce
[[1],[2],[3]].reduce([], +)
// Output: [1, 2, 3]

【讨论】:

    【解决方案4】:

    自 Swift 2.0 以来我最喜欢的方法是 flatten

    var a:[CGFloat] = [1, 2, 3]
    var b:[CGFloat] = [4, 5, 6]
    
    let c = [a, b].flatten()
    

    这将返回FlattenBidirectionalCollection,所以如果您只想要CollectionType,这就足够了,您将免费获得惰性评估。如果您确实需要数组,您可以这样做:

    let c = Array([a, b].flatten())
    

    【讨论】:

    • flatten() 现在似乎不存在了。不过你可以考虑joined()
    【解决方案5】:

    要完成可能的替代方案列表,reduce 可用于实现 flatten 的行为:

    var a = ["a", "b", "c"] 
    var b = ["d", "e", "f"]
    
    let res = [a, b].reduce([],combine:+)
    

    提供的最佳替代方案(性能/内存方面)只是flatten,它只是懒惰地包装原始数组而不创建新的数组结构。

    但请注意,flatten 不会返回 LazyCollection,因此惰性行为不会传播到链上的下一个操作(map、flatMap、filter , 等等...)。

    如果惰性在您的特定情况下有意义,请记住在 flatten() 前添加或附加 .lazy,例如,以这种方式修改 Tomasz 示例:

    let c = [a, b].lazy.flatten()
    

    【讨论】:

    • 这个答案在 2019 年与 Swift 5.1 的关系如何?
    • flatten() 不再存在。可以使用joined() 代替flatten()
    【解决方案6】:

    斯威夫特 4.X

    我知道的最简单的方法就是使用 + 号

    var Array1 = ["Item 1", "Item 2"]
    var Array2 = ["Thing 1", "Thing 2"]
    
    var Array3 = Array1 + Array2
    
    // Array 3 will just be them combined :)
    

    【讨论】:

      【解决方案7】:

      如果您希望在特定索引之后插入第二个数组,您可以这样做(从 Swift 2.2 开始):

      let index = 1
      if 0 ... a.count ~= index {
           a[index..<index] = b[0..<b.count]
      }
      print(a) // [1.0, 4.0, 5.0, 6.0, 2.0, 3.0] 
      

      【讨论】:

        【解决方案8】:

        Swift 3.0

        您可以通过使用加法运算符 (+) 将两个具有兼容类型的现有数组相加来创建一个新数组。新数组的类型是从你相加的两个数组的类型推断出来的,

        let arr0 = Array(repeating: 1, count: 3) // [1, 1, 1]
        let arr1 = Array(repeating: 2, count: 6)//[2, 2, 2, 2, 2, 2]
        let arr2 = arr0 + arr1 //[1, 1, 1, 2, 2, 2, 2, 2, 2]
        

        这是上面代码的正确结果。

        【讨论】:

          【解决方案9】:
          var arrayOne = [1,2,3]
          var arrayTwo = [4,5,6]
          

          如果您希望结果为:[1,2,3,[4,5,6]]

          arrayOne.append(arrayTwo)
          

          以上代码将arrayOne转换为单个元素并将其添加到arrayTwo的末尾。

          如果您希望结果为:[1, 2, 3, 4, 5, 6] 那么,

          arrayOne.append(contentsOf: arrayTwo)
          

          上面的代码会将arrayOne的所有元素添加到arrayTwo的末尾。

          谢谢。

          【讨论】:

            【解决方案10】:

            这是合并两个数组的最短方法。

             var array1 = [1,2,3]
             let array2 = [4,5,6]
            

            连接/合并它们

            array1 += array2
            New value of array1 is [1,2,3,4,5,6]
            

            【讨论】:

              【解决方案11】:

              同样,使用数组字典可以:

              var dict1 = [String:[Int]]()
              var dict2 = [String:[Int]]()
              dict1["key"] = [1,2,3]
              dict2["key"] = [4,5,6]
              dict1["key"] = dict1["key"]! + dict2["key"]!
              print(dict1["key"]!)
              

              如果“键”匹配,您可以遍历 dict1 并添加 dict2

              【讨论】:

                【解决方案12】:

                所以这个问题真的很需要flatMap,不需要自己重新实现或者使用reduce:

                var a:[CGFloat] = [1, 2, 3]
                var b:[CGFloat] = [4, 5, 6]
                let merged = [a, b].flatMap { $0 }
                

                就是这样 - 玩得开心?

                【讨论】:

                  【解决方案13】:

                  一种更有效的方法是使用 Apple 制作的 Algorithms 包中定义的 chain 方法。

                  let numbers1 = [1, 2, 3, 4]
                  let numbers2 = [5, 6, 7, 8]
                  
                  let allNumbers = chain(numbers1, numbers2)
                  for num in allNumbers {
                      print(num)
                  }
                  // for loop prints 1 to 8
                  

                  它还可以用于混合序列类型,例如整数数组和整数范围

                  let numbers = chain([10, 20, 30], 1...5)
                  // looping numbers will produce 10, 20, 30, 1, 2, 3, 4, 5
                  

                  同样适用于字符串

                  let letters = chain("foo", "BAR")
                  // "fooBAR"
                  

                  + 运算符或上述任何其他方法相比,Chain 的效率更高,因为它在连接时不会创建新的数组副本。

                  它本质上是迭代第一个序列,当它在第一个序列中遇到 endIndex 时,它开始无缝地迭代第二个序列。

                  【讨论】:

                    【解决方案14】:

                    Swift 5 数组扩展

                    extension Array where Element: Sequence {
                        func join() -> Array<Element.Element> {
                            return self.reduce([], +)
                        }
                    }
                    

                    例子:

                    let array = [[1,2,3], [4,5,6], [7,8,9]]
                    print(array.join())
                    
                    //result: [1, 2, 3, 4, 5, 6, 7, 8, 9]
                    

                    【讨论】:

                    • 一个小小的挑剔 - 我相信如果你的函数实际上返回一个数组,它应该被称为 joined() 而不是 join()
                    • 我定义了一个名为join的函数。请看上面的扩展。
                    【解决方案15】:

                    不同数据类型的Marge数组:

                    var arrayInt = [Int]()
                    arrayInt.append(6)
                    var testArray = ["a",true,3,"b"] as [Any]
                    testArray.append(someInt)
                    

                    输出:

                    ["a", true, 3, "b", "hi", 3, [6]]
                    

                    【讨论】:

                      猜你喜欢
                      • 2021-08-31
                      • 1970-01-01
                      • 2019-08-12
                      • 2021-08-29
                      • 2018-09-17
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多