Use a function to find common elements in two sequences in Swift

前端 未结 8 794
时光说笑
时光说笑 2020-12-30 00:07

I\'m trying to complete the exercise on page 46 of Apple\'s new book \"The Swift Programming Language\". It gives the following code:

func anyCommonElements         


        
相关标签:
8条回答
  • 2020-12-30 00:46

    From Swift 3, Generator protocol is renamed Iterator protocol : (link to github proposal)

    So, the function need to be written:

    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
    }
    
    0 讨论(0)
  • 2020-12-30 00:47

    In the most recent version of Swift (5.1), the following code works:

    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])
    
    0 讨论(0)
  • 2020-12-30 00:47

    The problem was to define the return value as an array so that was possible to add element to it.

    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]));
    
    0 讨论(0)
  • 2020-12-30 00:51

    Although this question has been answered, and the original question was about working with generic arrays, there is a way using Set and improving the stackoverflow knowledge base I still want to post it.

    The swift class Set contains these four methods:

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

    which are documented here: https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_Set_Structure/index.html

    You can convert two arrays into sets and use these methods:

    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]
    

    Edit 1:

    Like Martin R mentioned in a comment, the type of Set<T> has to inherit the protocol Hashable, which is slightly more restrictive than Equatable. And also the order of elements is not preserved, therefore consider the relevance of ordered elements!

    0 讨论(0)
  • 2020-12-30 00:55

    I was able to get it to work by making the return value an Array of 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])
    
    0 讨论(0)
  • 2020-12-30 01:02

    I had compiler errors with the above two solutions, I am running the guide from the iBook in the Xcode 6.01 playground. I had consistent compiler complaints about array declarations I found here so I am assuming the posters may be using an earlier version of swift. If I'm wrong, it would be great to know.

    For array declarations, I have found that

        var thingList : [ThingType] = []
    

    has worked consistently, so I tended to go with that, forsaking

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

    My environment never was able to resolve a thing called T.GeneratorType[.Element]

    The solution I came up for this experiment is


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

    The tutorial text really did not properly prepare me at all to actually solve the experiments without a lot of additional reading. Thanks to everyone here for contributing their solutions, it has really helped me get a great introduction to Swift.

    0 讨论(0)
提交回复
热议问题