与 Swift `zip` 相反——将元组拆分为两个数组 [英] Opposite of Swift `zip` — split tuple into two arrays

查看:31
本文介绍了与 Swift `zip` 相反——将元组拆分为两个数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个键值对数组:

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

我将其拆分为两个数组,如下所示:

I'm splitting it into two arrays, like this:

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

实际上,这与 zip 相反——我将一个元组数组变成两个数组.

Effectively, that's the opposite of zip — I'm turning an array of tuples into two arrays.

但我不喜欢我两次调用 map 的事实,因为这意味着我要遍历数组两次.然而,我也不想事先将两个目标数组声明为空数组并在附加时循环一次,例如与 forEach.是否有一些很棒的 Swifty 习惯用法可以将我的元组数组解压缩为两个数组?

But I don't like the fact that I'm calling map twice, because that means I'm looping through the array twice. Yet neither do I want to declare the two target arrays beforehand as empty arrays and loop once while appending, e.g. with forEach. Is there some wonderful Swifty idiom for unzipping my array of tuples into two arrays?

推荐答案

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

In Swift 4, you can use reduce(into:):

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

你说:

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

Yet neither do I want to declare the two target arrays beforehand as empty arrays and loop once while appending, e.g. with forEach.

就我个人而言,这正是我会做的.我只想编写一个执行此操作的函数(这样您就不会用该模式散布代码).但是我认为下面的内容比 reduce 模式要清晰和直观得多,而且不会遭受双 map 方法的低效率.

Personally, that's precisely what I would do. I would just write a function that does this (that way you're not sprinkling your code with that pattern). But I think the following is much more clear and intuitive than the reduce pattern, but doesn't suffer the inefficiency of the dual-map approach.

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

或者,如果您觉得有必要将其设为扩展,您也可以这样做:

Or, if you feel compelled to make it an extension, you can do that, too:

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

随心所欲地实现它,但是当你在一个函数中使用它时,你可以支持清晰和意图.

Implement this however you'd like, but when you have it in a function, you can favor clarity and intent.

这篇关于与 Swift `zip` 相反——将元组拆分为两个数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆