代码之家  ›  专栏  ›  技术社区  ›  matt

与Swift“zip”相反,将元组拆分为两个数组

  •  10
  • matt  · 技术社区  · 8 年前

    我有一个键值对数组:

    let arr = [(key:"hey", value:["ho"]), (key:"ha", value:["tee", "hee"])]
    

    我把它分成两个数组,如下所示:

    let (keys, values) = (arr.map{$0.key}, arr.map{$0.value})
    

    zip 我把一个元组数组变成两个数组。

    map forEach . 有什么很棒的快速习惯用法可以将元组数组解压为两个数组吗?

    3 回复  |  直到 8 年前
        1
  •  11
  •   Rob Md Fahim Faez Abir    8 年前

    在Swift 4中,您可以使用 reduce(into:)

    let (keys, values) = arr.reduce(into: ([String](), [[String]]())) {
        $0.0.append($1.key)
        $0.1.append($1.value)
    }
    

    你说:

    然而,我也不想事先将两个目标数组声明为空数组,并在附加时循环一次,例如 forEach

    就我个人而言,这正是我要做的。我只需要编写一个函数来实现这一点(这样你就不会在代码中散布这种模式)。但我认为以下内容比 reduce map 方法

    /// Unzip an `Array` of key/value tuples.
    ///
    /// - Parameter array: `Array` of key/value tuples.
    /// - Returns: A tuple with two arrays, an `Array` of keys and an `Array` of values.
    
    func unzip<K, V>(_ array: [(key: K, value: V)]) -> ([K], [V]) {
        var keys = [K]()
        var values = [V]()
    
        keys.reserveCapacity(array.count)
        values.reserveCapacity(array.count)
    
        array.forEach { key, value in
            keys.append(key)
            values.append(value)
        }
    
        return (keys, values)
    }
    

    extension

    extension Array {
    
        /// Unzip an `Array` of key/value tuples.
        ///
        /// - Returns: A tuple with two arrays, an `Array` of keys and an `Array` of values.
    
        func unzip<K, V>() -> ([K], [V]) where Element == (key: K, value: V) {
            var keys = [K]()
            var values = [V]()
    
            keys.reserveCapacity(count)
            values.reserveCapacity(count)
    
            forEach { key, value in
                keys.append(key)
                values.append(value)
            }
    
            return (keys, values)
        }
    }
    

    不管你想怎样实现它,但是当你在函数中有了它,你可以倾向于清晰和意图。

        2
  •  8
  •   Alexander    7 年前

    reduce(into:) 很好,但别忘了 reserveCapacity 为了防止重新分配开销:

    extension Array {
        func unzip<T1, T2>() -> ([T1], [T2]) where Element == (T1, T2) {
            var result = ([T1](), [T2]())
    
            result.0.reserveCapacity(self.count)
            result.1.reserveCapacity(self.count)
    
            return reduce(into: result) { acc, pair in
                acc.0.append(pair.0)
                acc.1.append(pair.1)
            }
        }
    }
    

    extension Array {
        func unzip<T1, T2>() -> ([T1], [T2]) where Element == (T1, T2) {
            var result = ([T1](), [T2]())
    
            result.0.reserveCapacity(self.count)
            result.1.reserveCapacity(self.count)
    
            for (a, b) in self {
                result.0.append(a)
                result.1.append(b)
            }
    
            return result
        }
    }
    
    let arr = [
        (key: "hey", value: ["ho"]),
        (key: "ha",  value: ["tee", "hee"])
    ]
    
    let unzipped = (arr as [(String, [String])]).unzip()
    print(unzipped)
    
        3
  •  1
  •   luk2302    8 年前

    虽然不好看,但我现在唯一能想到的是:使用 reduce :

    let (keys, values) = arr.reduce(([], [])) { ($0.0.0 + [$0.1.key], $0.0.1 + [$0.1.value]) }
    

    func unzip<K,V>(_ array : [(K,V)]) -> ([K], [V]) {
        return array.reduce(([], [])) { ($0.0 + [$1.0], $0.1 + [$1.1])}
    }
    
    let (keys, values) = unzip(arr)