Используйте функцию для поиска общих элементов в двух последовательностях в Swift
Я пытаюсь выполнить упражнение на странице 46 новой книги Apple "Язык быстрого языка". Он дает следующий код:
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 я получаю ошибку: не удалось найти член "нижний индекс"
В чем причина этой ошибки и наилучшее решение этой проблемы?
Ответы
Ответ 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])
Ответ 2
У меня были ошибки компилятора с двумя вышеупомянутыми решениями, я запускаю руководство от iBook на игровой площадке Xcode 6.01. У меня были последовательные жалобы компилятора на объявления массива, которые я нашел здесь, поэтому я предполагаю, что плакаты могут использовать более раннюю версию Quick. Если я ошибаюсь, было бы здорово знать.
Для объявлений массива я обнаружил, что
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
От Swift 3 протокол Генератор переименован в протокол Итератор: (ссылка на предложение github)
Итак, функция должна быть записана:
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
}
Ответ 4
Проблема заключалась в том, чтобы определить возвращаемое значение как массив, чтобы можно было добавить элемент к нему.
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]));
Ответ 5
Хотя на этот вопрос был дан ответ, и исходный вопрос заключался в работе с универсальными массивами, существует способ использования Set
и улучшения базы знаний stackoverflow, которую я все еще хочу опубликовать.
Быстрый класс 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:
Как и Мартин Р, упомянутый в комментарии, тип Set<T>
должен наследовать протокол Hashable
, который немного более ограничительный, чем Equatable
.
А также порядок элементов не сохраняется, поэтому рассмотрим релевантность упорядоченных элементов!
Ответ 6
Принятый ответ больше недействителен для последней версии 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
Самый чистый способ решения этой проблемы в 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) }
}