我有三个我试图运行的数组,我想在一个函数中使用所有三个数组的值。这可能听起来令人困惑,但这就是我所拥有的:
var Name = [Joe, Sarah, Chad]
var Age = [18, 20, 22]
var Gender = [Male, Female, Male]
for name in Name {
for age in Age {
for gender in Gender {
makeUser(name, userAge: age, userGender: gender)
}
}
}
这会运行,但我得到的是:( makeUser打印出3个值)
Joe, 18, Male
Joe, 20, Male
Joe, 22, Male
Joe, 18, Female
Joe, 20, Female
Joe, 22, Female ....
等等。
我想要的只是
Joe, 18, Male
Sarah, 20, Female
Chad, 22, Male
这可能吗?任何帮助表示赞赏。
谢谢!
答案 0 :(得分:20)
这是一个非常常见的要求,因此标准库通过函数zip
迎合它:*
for (a,b) in zip(seq1, seq2) {
// a and b will be matching pairs from the two sequences
}
不幸的是,截至目前,zip
只进行配对,即使理论上它可能会超载三倍。但是,这不是什么大问题,你可以嵌套它们:
var names = ["Joe", "Sarah", "Chad"]
var ages = [18, 20, 22]
var genders: [Gender] = [.Male, .Female, .Male]
for (name,(age,gender)) in zip(names,zip(ages,genders)) {
makeUser(name, userAge: age, userGender: gender)
}
请注意,它只会提供最短的序列,因此如果名称多于年龄或性别,则只能获得匹配的名称。
与使用索引相比,这似乎有点不利,这看起来似乎也更复杂,但替代方案的简单性具有欺骗性。请记住,如果您使用indices
或enumerate
以及不匹配的数组会发生什么情况 - 您将获得一个超出边界断言的数组(或者您必须放入检查逻辑) 。
zip
避免了这个问题。它还意味着您可以使用序列而不是集合,以及使用不具有整数索引(不同于enumerate
)的集合或具有不同索引类型的集合(例如String
和{ {1}})。
*(在当前的测试版中,无论如何 - Array
会返回zip
个对象。在Swift 1.1中,您需要直接创建Zip2
版本,因为Zip2
只有刚刚介绍过)
答案 1 :(得分:4)
如果你总是确定数组的长度是相等的,那么你最好循环遍历其中一个数组并使用它的索引来引用其他数组:
for (index, name) in enumerate(Name) {
makeUser(name, userAge: Age[index], userGender: Gender[index])
}
但是,我建议将这些数据放入字典中,但我认为这只是示例数据来说明一点。 :)
答案 2 :(得分:2)
您可以使用自定义zip3
功能,这并不难写。
struct Zip3Sequence<E1, E2, E3>: Sequence, IteratorProtocol {
private let _next: () -> (E1, E2, E3)?
init<S1: Sequence, S2: Sequence, S3: Sequence>(_ s1: S1, _ s2: S2, _ s3: S3) where S1.Element == E1, S2.Element == E2, S3.Element == E3 {
var it1 = s1.makeIterator()
var it2 = s2.makeIterator()
var it3 = s3.makeIterator()
_next = {
guard let e1 = it1.next(), let e2 = it2.next(), let e3 = it3.next() else { return nil }
return (e1, e2, e3)
}
}
mutating func next() -> (E1, E2, E3)? {
return _next()
}
}
func zip3<S1: Sequence, S2: Sequence, S3: Sequence>(_ s1: S1, _ s2: S2, _ s3: S3) -> Zip3Sequence<S1.Element, S2.Element, S3.Element> {
return Zip3Sequence(s1, s2, s3)
}
let names = ["Joe", "Sarah", "Chad"]
let ages = [18, 20, 22]
let genders = ["Male", "Female", "Male"]
for (name, age, gender) in zip3(names, ages, genders) {
print("Name: \(name), age: \(age), gender: \(gender)")
}
以上代码打印:
Name: Joe, age: 18, gender: Male
Name: Sarah, age: 20, gender: Female
Name: Chad, age: 22, gender: Male
答案 3 :(得分:1)
这是一个使用zip
和3个数组的解决方案(测试它们的长度确实相同):
for (name, (age, gender)) in zip(names, zip(ages, genders)) {
makeUser(name, userAge: age, userGender: gender)
}
但也许最干净的只是老式的C风格:
for i in 0..<names.count {
let name = names[i]
let age = ages[i]
let gender = genders[i]
makeUser(name, userAge: age, userGender: gender)
}
答案 4 :(得分:0)
见下文。但是,如果这些数组中的任何数组与其他数组的大小不同,则代码将崩溃。
var Name = ["a", "b", "c"]
var Age = [1, 2, 3]
var Gender = ["m", "f", "m"]
for (var i = 0; i<Name.count; i++) {
var name = Name[i]
var age = Age[i]
var gender = Gender[i]
makeUser(name, userAge: age, userGender: gender)
}
答案 5 :(得分:0)
您可以将枚举数转换为数组,并使用函数方法将结果映射到您想要的结果。
var Name = ["a", "b", "c"]
var Age = [1, 2, 3]
var Gender = ["m", "f", "m"]
let results = Array(Name.enumerated())
.map {($0.element, Age[$0.index], Gender[$0.index])}