考虑以下愚蠢而简单的例子:
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 { /* ???? */ }
如果不能做到这一点没什么大不了的,但能够以这种方式说话会很有趣。
答案 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"]