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
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
}
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])
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]));
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!
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])
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.