我正在尝试完成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行,我收到错误:无法找到成员'下标'
出现此错误的原因是什么?此问题的最佳解决方案是什么?
答案 0 :(得分:27)
通过使返回值为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])
答案 1 :(得分:9)
从Swift 3开始,生成器协议重命名为 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
}
答案 2 :(得分:8)
我在上述两个解决方案中遇到了编译错误,我正在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进行了很好的介绍。
答案 3 :(得分:1)
问题是将返回值定义为数组,以便可以向其添加元素。
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]));
答案 4 :(得分:1)
在最新版本的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])
答案 5 :(得分:0)
虽然这个问题已经得到解答,而最初的问题是关于使用泛型数组,但有一种方法可以使用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<T>
的类型必须继承协议Hashable
,这比Equatable
稍微限制一些。
并且元素的顺序也不会被保留,因此请考虑有序元素的相关性!
答案 6 :(得分:0)
接受的答案不再适用于最新版本的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"])
答案 7 :(得分:0)
在Swift 3中解决这个问题的最简单方法是使用过滤函数,如下所示:
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) }
}