【问题标题】:How can I run through three separate arrays in the same for loop?如何在同一个 for 循环中运行三个单独的数组?
【发布时间】:2015-04-25 12:51:48
【问题描述】:

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

    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

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

谢谢!

【问题讨论】:

    标签: arrays swift


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      这是一个使用 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)
      }
      

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 请在上面添加答案。
        【解决方案4】:

        这是一个非常常见的要求,因此标准库通过一个函数来满足它,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)
        }
        

        注意,它只会提供最短的序列,所以如果名字多于年龄或性别,你只会得到匹配的名字。

        与使用索引相比,这似乎是不利的一面,而且这似乎也更复杂,但替代方案的简单性具有欺骗性。请记住,如果您将indicesenumerate 与不匹配的数组一起使用会发生什么——您会得到一个数组越界断言(或者您必须放入检查逻辑)。

        zip 避免了这个问题。这也意味着您可以使用序列而不是集合,以及使用没有整数索引的集合(与enumerate 不同)或具有不同索引类型的集合(例如StringArray)。

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

        【讨论】:

          【解决方案5】:

          见下文。但是,如果其中任何一个数组的大小与其他数组不同,您的代码就会崩溃。

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

          【讨论】:

            【解决方案6】:

            如果您始终确定数组的长度相等,那么您最好只循环其中一个数组并使用它的索引来引用其他数组:

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

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

            【讨论】:

            • .现在枚举
            猜你喜欢
            • 2016-01-15
            • 1970-01-01
            • 1970-01-01
            • 2019-12-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多