如何在同一个for循环中运行三个单独的数组?

时间:2021-09-04 14:09:05

I have three arrays I am trying to run through and I want to use the values from all three arrays in one function. This might sound confusing but here is what I have:

我有三个我试图运行的数组,我想在一个函数中使用所有三个数组的值。这可能听起来令人困惑,但这就是我所拥有的:

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

This runs but what I get is: (makeUser prints out the 3 values)

这运行但我得到的是:( makeUser打印出3个值)

Joe, 18, Male
Joe, 20, Male
Joe, 22, Male

Joe, 18, Female
Joe, 20, Female
Joe, 22, Female ....

And so on.

等等。

All I want is

我只想要的是

Joe, 18, Male
Sarah, 20, Female
Chad, 22, Male

Is this possible? Any help is appreciated.

这可能吗?任何帮助表示赞赏。

Thanks!

谢谢!

6 个解决方案

#1


4  

If you are always sure the arrays will be equal in length, then you are better to just loop through one of the arrays and use it's index to reference the others:

如果你总是确定数组的长度是相等的,那么你最好循环遍历其中一个数组并使用它的索引引用其他数组:

for (index, name) in enumerate(Name) {
    makeUser(name, userAge: Age[index], userGender: Gender[index])
}

However, I would recommend getting this data into a dictionary, but I assume this is just sample data to illustrate a point. :)

但是,我建议将这些数据放入字典中,但我认为这只是示例数据来说明一点。 :)

#2


15  

This is a very common requirement so the standard library caters to it with a function, zip:*

这是一个非常常见的要求,所以标准库提供了一个功能,zip:*

for (a,b) in zip(seq1, seq2) {
    // a and b will be matching pairs from the two sequences
}

Unfortunately, as of right now, zip only does pairs, even though in theory it could be overloaded to do triples. However, it’s not a big deal, you can just nest them:

不幸的是,截至目前,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)
}

Note, it will only serve up to the shortest sequence, so if there are more names than ages or genders, you’ll only get the matching names.

请注意,它只能提供最短的序列,因此如果名称多于年龄或性别,您将只获得匹配的名称。

This might seem like a down side compared to using an index, and this might also seem more complex, but the alternative’s simplicity is deceptive. Bear in mind what would happen if you used indices or enumerate alongside arrays that didn’t match – you’d get an array out of bounds assertion (or you’d have to put in checking logic).

与使用索引相比,这看起来似乎是一个缺点,这似乎也更复杂,但替代方案的简单性具有欺骗性。请记住,如果您使用索引或枚举与不匹配的数组一起会发生什么 - 您将获得一个超出边界断言的数组(或者您必须放入检查逻辑)。

zip avoids this problem. It also means you can use sequences instead of collections, as well as working with collections that don’t have integer indices (unlike enumerate) or collections that have different index types (e.g. a String and an Array).

zip避免了这个问题。它还意味着您可以使用序列而不是集合,以及使用不具有整数索引(与枚举不同)的集合或具有不同索引类型的集合(例如,字符串和数组)。

*(in the current beta, anyway – zip returns a Zip2 object. In Swift 1.1, you need to create the Zip2 version directly as zip has only just been introduced)

*(在当前的测试版中,无论如何 - zip返回一个Zip2对象。在Swift 1.1中,你需要直接创建Zip2版本,因为刚刚引入了zip)

#3


1  

You could use a custom zip3 function, which is not hard to write.

您可以使用自定义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)")
}

The above code prints:

上面的代码打印:

Name: Joe, age: 18, gender: Male
Name: Sarah, age: 20, gender: Female
Name: Chad, age: 22, gender: Male

#4


0  

See below. However, your code will crash if any of these arrays differs in size from the others.

见下文。但是,如果这些数组中的任何数组与其他数组的大小不同,则代码将崩溃。

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  

You can cast the enumerator as an array and use functional methods to map the result to what you want.

您可以将枚举器强制转换为数组,并使用函数方法将结果映射到您想要的结果。

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

#6


0  

Here is a solution using zip with 3 arrays (test they are indeed the same length):

这是一个使用带有3个数组的zip的解决方案(测试它们的长度确实相同):

for (name, (age, gender)) in zip(names, zip(ages, genders)) {
    makeUser(name, userAge: age, userGender: gender)
}

But maybe the cleanest of them all is just old fashioned C-style:

但也许最干净的只是老式的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)
}

#1


4  

If you are always sure the arrays will be equal in length, then you are better to just loop through one of the arrays and use it's index to reference the others:

如果你总是确定数组的长度是相等的,那么你最好循环遍历其中一个数组并使用它的索引引用其他数组:

for (index, name) in enumerate(Name) {
    makeUser(name, userAge: Age[index], userGender: Gender[index])
}

However, I would recommend getting this data into a dictionary, but I assume this is just sample data to illustrate a point. :)

但是,我建议将这些数据放入字典中,但我认为这只是示例数据来说明一点。 :)

#2


15  

This is a very common requirement so the standard library caters to it with a function, zip:*

这是一个非常常见的要求,所以标准库提供了一个功能,zip:*

for (a,b) in zip(seq1, seq2) {
    // a and b will be matching pairs from the two sequences
}

Unfortunately, as of right now, zip only does pairs, even though in theory it could be overloaded to do triples. However, it’s not a big deal, you can just nest them:

不幸的是,截至目前,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)
}

Note, it will only serve up to the shortest sequence, so if there are more names than ages or genders, you’ll only get the matching names.

请注意,它只能提供最短的序列,因此如果名称多于年龄或性别,您将只获得匹配的名称。

This might seem like a down side compared to using an index, and this might also seem more complex, but the alternative’s simplicity is deceptive. Bear in mind what would happen if you used indices or enumerate alongside arrays that didn’t match – you’d get an array out of bounds assertion (or you’d have to put in checking logic).

与使用索引相比,这看起来似乎是一个缺点,这似乎也更复杂,但替代方案的简单性具有欺骗性。请记住,如果您使用索引或枚举与不匹配的数组一起会发生什么 - 您将获得一个超出边界断言的数组(或者您必须放入检查逻辑)。

zip avoids this problem. It also means you can use sequences instead of collections, as well as working with collections that don’t have integer indices (unlike enumerate) or collections that have different index types (e.g. a String and an Array).

zip避免了这个问题。它还意味着您可以使用序列而不是集合,以及使用不具有整数索引(与枚举不同)的集合或具有不同索引类型的集合(例如,字符串和数组)。

*(in the current beta, anyway – zip returns a Zip2 object. In Swift 1.1, you need to create the Zip2 version directly as zip has only just been introduced)

*(在当前的测试版中,无论如何 - zip返回一个Zip2对象。在Swift 1.1中,你需要直接创建Zip2版本,因为刚刚引入了zip)

#3


1  

You could use a custom zip3 function, which is not hard to write.

您可以使用自定义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)")
}

The above code prints:

上面的代码打印:

Name: Joe, age: 18, gender: Male
Name: Sarah, age: 20, gender: Female
Name: Chad, age: 22, gender: Male

#4


0  

See below. However, your code will crash if any of these arrays differs in size from the others.

见下文。但是,如果这些数组中的任何数组与其他数组的大小不同,则代码将崩溃。

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  

You can cast the enumerator as an array and use functional methods to map the result to what you want.

您可以将枚举器强制转换为数组,并使用函数方法将结果映射到您想要的结果。

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

#6


0  

Here is a solution using zip with 3 arrays (test they are indeed the same length):

这是一个使用带有3个数组的zip的解决方案(测试它们的长度确实相同):

for (name, (age, gender)) in zip(names, zip(ages, genders)) {
    makeUser(name, userAge: age, userGender: gender)
}

But maybe the cleanest of them all is just old fashioned C-style:

但也许最干净的只是老式的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)
}