Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

swift

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

The exercise is to change the function so that all elements that both sequences have are returned. To do this I tried to use the following code:

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

But on line 2, I get the error: Could not find the member 'subscript'

What is the reason for this error and what is the best solution to this problem?

like image 864
user3705142 Avatar asked Jun 04 '14 00:06

user3705142


3 Answers

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])
like image 158
Connor Avatar answered Dec 15 '22 09:12

Connor


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
}
like image 41
Nicolas Buquet Avatar answered Dec 15 '22 11:12

Nicolas Buquet


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.

like image 45
Socrates Avatar answered Dec 15 '22 11:12

Socrates