Swift数组循环一次,写很多

时间:2015-06-10 15:51:07

标签: arrays swift dictionary

考虑以下愚蠢而简单的例子:

let arr = ["hey", "ho"]
let doubled = arr.map {$0 + $0}
let capitalized = arr.map {$0.capitalizedString}

正如您所看到的,我正在以多种方式处理相同的初始数组,以便最终得到多个已处理的数组。

现在假设arr非常长并且我有很多这样的进程生成许多最终数组。我不喜欢上面的代码,因为我们循环多次,每次map调用一次。我宁愿只循环一次。

现在,显然我们可以通过强力处理这个问题,即从多个可变数组开始并在每次迭代时写入所有数组:

let arr = ["hey", "ho"]
var doubled = [String]()
var capitalized = [String]()
for s in arr {
    doubled.append(s + s)
    capitalized.append(s.capitalizedString)
}

精细。但是现在我们没有得到使用map的乐趣。所以我的问题是:有更好的,更快捷的方式吗?以一种朦胧的方式,我想我自己使用map,或类似map之类的东西来生成类似元组的东西,并且在我们迭代时神奇地将该元组拆分为所有生成的数组,就好像我可以说类似这个(伪代码,不要在家里试试):

let arr = ["hey", "ho"]
let (doubled, capitalized) = arr.map { /* ???? */ }

如果我正在设计自己的语言,我甚至可以通过赋值给一个伪数组左右来允许一种splatting:

let arr = ["hey", "ho"]
let [doubled, capitalized] = arr.map { /* ???? */ }

如果不能做到这一点没什么大不了的,但能够以这种方式说话会很有趣。

3 个答案:

答案 0 :(得分:2)

一个函数multimap如何获取转换集合并应用每个转换,将它们作为数组数组返回:

// yay protocol extensions
extension SequenceType {
    // looks like T->U works OK as a constraint
    func multimap
      <U, C: CollectionType 
       where C.Generator.Element == Generator.Element->U>
    (transformations: C) -> [[U]] {
        return transformations.map {
            self.map($0)
        }
    }
}

然后像这样使用它:

let arr = ["hey", "ho"]

let double: String->String = { $0 + $0 }
let uppercase: String->String = { $0.uppercaseString }

arr.multimap([double, uppercase])
// returns [["heyhey", "hoho"], ["HEY", "HO"]]

或者它在可变形式中可能相当不错:

extension SequenceType {
    func multimap<U>(transformations: (Generator.Element->U)...) -> [[U]] {
        return self.multimap(transformations)
    }
}

arr.multimap({ $0 + $0 }, { $0.uppercaseString })

编辑:如果你想要单独的变量,我认为你能做的最好的是一个destructure函数(你不得不为每个n元组声明n次):

// I don't think this can't be expressed as a protocol extension quite yet
func destructure<C: CollectionType>(source: C) -> (C.Generator.Element,C.Generator.Element) {
    precondition(source.count == 2)
    return (source[source.startIndex],source[source.startIndex.successor()])
}

// and, since it's a function, let's declare pipe forward
// to make it easier to call
infix operator |> { }
func |> <T,U>(lhs: T, rhs: T->U) -> U {
    return rhs(lhs)
}

然后你可以声明这样的变量:

let (doubled,uppercased)
    = arr.multimap({ $0 + $0 }, { $0.uppercaseString }) |> destructure

是的,这是一个有点低效的因为你必须构建数组然后把它拆开 - 但这真的不会是重要的,因为数组是写时复制的,我们谈的是少数它们在外部阵列中。

编辑:使用新guard语句的借口:

func destructure<C: Sliceable where C.SubSlice.Generator.Element == C.Generator.Element>(source: C) -> (C.Generator.Element,C.Generator.Element) {
    guard let one = source.first else { fatalError("empty source") }
    guard let two = dropFirst(source).first else { fatalError("insufficient elements") }

    return (one,two)
}

答案 1 :(得分:2)

你对元组的建议有什么问题?

let arr = ["hey", "ho"]

let  mapped = arr.map {e in
  return (e + e, e.capitalizedString)
}

答案 2 :(得分:0)

这个怎么样,我们在映射'doubled'数组时处理'大写'数组:

let arr = ["hey", "ho"]

var capitalized = [String]()
let doubled = arr.map {(var myString) -> String in
    capitalized.append(myString.capitalizedString)
    return myString + myString
} 

//doubled ["heyhey", "hoho"]
//capitalized: ["Hey", "Ho"]