Подтвердить что ты не робот

Используйте функцию для поиска общих элементов в двух последовательностях в 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 я получаю ошибку: не удалось найти член "нижний индекс"

В чем причина этой ошибки и наилучшее решение этой проблемы?

4b9b3361

Ответ 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) }
}