【问题标题】:Use a function to find common elements in two sequences in Swift在 Swift 中使用函数查找两个序列中的共同元素
【发布时间】:2014-06-04 00:47:13
【问题描述】:

我正在尝试完成 Apple 新书“The Swift Programming Language”第 46 页的练习。它给出了以下代码:

func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Bool {
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                return true
            }
        }
    }
    return false
}
anyCommonElements([1, 2, 3], [3])

练习是更改函数,以便返回两个序列具有的所有元素。为此,我尝试使用以下代码:

func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element:     Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> T.GeneratorType[] {
    var toReturn = T.GeneratorType[]()
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                toReturn.append(lhsItem)
            }
        }
    }
    return toReturn
}
anyCommonElements([1, 2, 3], [3])

但在第 2 行,我收到错误:找不到成员“下标”

此错误的原因是什么?解决此问题的最佳方法是什么?

【问题讨论】:

    标签: swift


    【解决方案1】:

    我能够通过将返回值设为 T.GeneratorType.Element 数组来使其工作。

    func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> Array<T.Generator.Element> {
        var toReturn = Array<T.Generator.Element>()
        for lhsItem in lhs {
            for rhsItem in rhs {
                if lhsItem == rhsItem {
                    toReturn.append(lhsItem)
                }
            }
        }
        return toReturn
    }
    anyCommonElements([1, 2, 3], [3])
    

    【讨论】:

    • 您的评论说您返回 T.GeneratorType.Element,但它只返回 T。我正在发布我的版本来纠正这个问题。
    • @TimRupe,这是来自建议的编辑。感谢您发现错误
    • 知道为什么 var toReturn = Array() 有效但 var toReturn = [T.GeneratorType.Element]() 会出错吗?
    • 这似乎是 XCode 崩溃
    • 这会导致 Xcode 6.0.1 崩溃,最好使用下面的苏格拉底数组声明:var toReturn: [T.Generator.Element] = [] 以保持工作正常
    【解决方案2】:

    从 Swift 3 开始,Generator 协议被重命名为 Iterator 协议:(link to github proposal)

    所以,需要编写函数:

    func commonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element]
        where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
            var common: [T.Iterator.Element] = []
    
            for lhsItem in lhs {
                for rhsItem in rhs {
                    if lhsItem == rhsItem {
                        common.append(lhsItem)
                    }
                }
            }
            return common
    }
    

    【讨论】:

    • 现在这是正确的答案,直到苹果决定重新命名某些东西,似乎每个新版本都是如此。
    • 这是与当前 Swift 语法同步的更新答案。
    【解决方案3】:

    我在使用上述两种解决方案时遇到了编译器错误,我正在 Xcode 6.01 操场上运行 iBook 中的指南。我对在这里找到的数组声明有一致的编译器投诉,所以我假设海报可能使用的是早期版本的 swift。如果我错了,很高兴知道。

    对于数组声明,我发现

        var thingList : [ThingType] = []
    

    一直在工作,所以我倾向于放弃

        var thing[],thing[]()  // gave compiler errors/warnings
    

    我的环境永远无法解决一个名为 T.GeneratorType[.Element]

    我为这个实验想出的解决方案是


    func anyCommonElements <T, U
                        where
                        T: SequenceType, U: SequenceType,
                        T.Generator.Element: Equatable,
                        T.Generator.Element == U.Generator.Element>
                        (lhs: T, rhs: U)
    -> [T.Generator.Element]
    {
        var  returnValue: [T.Generator.Element] = []
        for lhsItem in lhs {
            for rhsItem in rhs {
               if lhsItem == rhsItem {
                  returnValue.append(lhsItem)
               }
            }
        }
        return returnValue
    }
    
    let commonNumberList = anyCommonElements([1, 2, 3,4,5,6,7,8], [2,3,9,14,8,21])
    println("common Numbers = \(commonNumberList)")
    
    let commonStringList = anyCommonElements(["a","b","c"],["d","e","f","c","b"])
    println("common Strings = \(commonStringList)")
    

    教程文本真的没有让我完全准备好在没有大量额外阅读的情况下实际解决实验。感谢在座各位贡献他们的解决方案,这真的帮助我很好地了解了 Swift。

    【讨论】:

    • 只有这对我有用。我同意必须阅读以解决Experiments。但我认为这也是他们的意图...... :)
    【解决方案4】:

    在 Swift 3 中解决这个问题的最简洁的方法是使用 filter 函数,如下所示:

    func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element]
        where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
            return lhs.filter { rhs.contains($0) }
    }
    

    【讨论】:

      【解决方案5】:

      在最新版本的 Swift (5.1) 中,以下代码有效:

      func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Array<T.Element>
          where T.Element: Equatable, T.Element == U.Element
      {
          var templist = Array<T.Element>()
          for lhsItem in lhs {
              for rhsItem in rhs {
                  if lhsItem == rhsItem {
                      templist.append(lhsItem)
                  }
              }
          }
         return templist
      }
      anyCommonElements([1, 2, 3], [3])
      

      【讨论】:

        【解决方案6】:

        问题是将返回值定义为一个数组,以便可以向其中添加元素。

        func anyCommonElements<T, U where T:SequenceType, U:SequenceType, 
        T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element >(lhs: T, rhs: U) -> Array <T.Generator.Element> {
           var result = Array <T.Generator.Element>();
           for lhsItem in lhs {
               for rhsItem in rhs {
                  if lhsItem == rhsItem {
                    result.append(lhsItem);
                  }
               }
          }
          return result;
        }
        
        print(anyCommonElements([1,3,7,9,6,8],rhs:[4,6,8]));
        

        【讨论】:

        • 我将其标记为低质量,原因如下:仅代码答案,未提供解释,代码无法编译(错误:一行上的连续语句必须用“; ")
        【解决方案7】:

        虽然这个问题已经得到解答,并且最初的问题是关于使用泛型数组,但有一种方法可以使用 Set 并改进 stackoverflow 知识库,我仍然想发布它。

        swift类Set包含这四个方法:

        Set.union(sequence:)
        Set.subtract(sequence:)
        Set.intersect(sequence:)
        Set.exclusiveOr(sequence:)
        

        在此处记录:https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_Set_Structure/index.html

        您可以将两个数组转换为集合并使用以下方法:

        let array1 = [1, 2, 3]
        let array2 = [3, 4]
        
        let set1 = Set<Int>(array1)
        let set2 = Set<Int>(array2)
        
        let union = set1.union(set2)                // [2, 3, 1, 4]
        let subtract = set1.subtract(set2)          // [2, 1]
        let intersect = set1.intersect(set2)        // [3]
        let exclusiveOr = set1.exclusiveOr(set2)    // [2, 4, 1]
        

        编辑 1:

        就像 Martin R 在评论中提到的那样,Set&lt;T&gt; 的类型必须继承协议Hashable,这比Equatable 限制性稍强。 并且元素的顺序也没有保留,因此请考虑有序元素的相关性!

        【讨论】:

        • 请注意,这要求元素为Hashable,这比Equatable 的限制性稍强。 – 另请注意,这不会保留元素的 order(可能相关或不相关)。
        • 已将您的注释添加到答案中。
        【解决方案8】:

        接受的答案对于最新版本的 Swift 不再有效。这是一个与 3.0.1 版本兼容的更新,他们简化了如何制作泛型数组。

        func showCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element]
            where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
                var result:[T.Iterator.Element] = []
                for lhsItem in lhs {
                    for rhsItem in rhs {
                        if lhsItem == rhsItem {
                            result.append(lhsItem)
                        }
                    }
                }
                return result
        }
        

        您可以使用以下命令测试代码:

        showCommonElements([1, 2, 3, 4, 5], [4, 7, 3])
        showCommonElements(["apple", "banana", "orange", "peach"], ["orange", "pear", "apple"])
        

        【讨论】:

          【解决方案9】:

          OrderedSet 让这一切变得简单,只要您的元素是 Hashable

          // [4, 6, 8, 10] as OrderedSet
          (1..<13).commonElements(with: stride(from: 4, through: 10, by: 2)) 
          
          import Collections
          
          public extension Sequence {
            func commonElements<Sequence: Swift.Sequence>(with sequence: Sequence) -> OrderedSet<Element>
            where Element == Sequence.Element {
              OrderedSet(self).intersection(sequence)
            }
          }
          

          【讨论】:

            【解决方案10】:

            Swift 5.6 的解决方案:

            func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Element]
              where T.Element: Equatable, T.Element == U.Element
            {
              var commonElements: [T.Element] = []
              for lhsItem in lhs {
                  for rhsItem in rhs {
                      if lhsItem == rhsItem {
                          commonElements.append(rhsItem)
                      }
                  }
              }
              return commonElements
            }
            

            【讨论】:

              【解决方案11】:

              这是 Swift 5.4 的有效解决方案:

              func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Element]
                  where T.Element: Equatable, T.Element == U.Element
              {
                  var commonElements = [T.Element]()
                  for lhsItem in lhs {
                      for rhsItem in rhs {
                          if lhsItem == rhsItem {
                              commonElements.append(lhsItem)
                          }
                      }
                  }
                  return commonElements
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-03-26
                • 1970-01-01
                • 2021-06-06
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-01-01
                • 1970-01-01
                相关资源
                最近更新 更多