2015-05-23 1 views
2

Я использую zip на двух массивах кортежей. Когда я повторяю результат, кортеж результата содержит кортежи только с левой стороны.Swift zip-генератор только итерации с одной стороны дважды

Интересно, что Array(zip(...)) производит коллекцию, как ожидалось. Я хочу сохранить несколько циклов и памяти и предпочитаю не генерировать новый массив только ради цикла.

let expectation: [(String, UInt)] = [("bar", 0)] 
let comparison: [(String, Int)] = [("foo", 0)] 

func ==(lhs: [(String, UInt)], rhs: [(String, Int)]) -> Bool { 
    if lhs.count != rhs.count { 
     return false 
    } 

    for (l, r) in zip(lhs, rhs) { 
     // Looking at `l` and `r` in lldb shows both are the same. 
     if l.0 != r.0 || Int(l.1) != r.1 { 
      return false 
     } 
    } 

    return true 
} 

let equals = (expectation == comparison) // true?!?! 

Этот метод предназначен для сравнения записей вызовов функций в двойном тестовом режиме для проверки данных из реальных тестовых случаев. Двойные записи (String, UInt), набирая кортежи в тестовых примерах, производит (String, Int), поэтому я подумал: давайте создадим легкую функцию равенства! Изменение UInt до Int ничего не меняет.

Как это сделать? Renders zip довольно бесполезен для меня (за исключением случаев, когда вы можете объяснить, что происходит).

ответ

3

Невозможно решить, является ли это ошибкой или что-то, что я не понимаю (подозрительная ошибка, но вам нужно больше поиграть с ней).

Однако здесь обходной путь в среднем времени, который включает в себя полностью уничтожение того, данные:

let expectation: [(String, UInt)] = [("bar", 0)] 
let comparison: [(String, Int)] = [("foo", 1)] 

func ==(lhs: [(String, UInt)], rhs: [(String, Int)]) -> Bool { 
    if lhs.count != rhs.count { 
     return false 
    } 

    for ((ls, li),(rs,ri)) in zip(lhs, rhs) { 
     // Looking at `l` and `r` in lldb shows both are the same. 
     if ls != rs || Int(li) != ri { 
      return false 
     } 
    } 

    return true 
} 

let equals = (expectation == comparison) // now returns false 

В теории, это должно быть более легко записать в виде:

equal(expectation, comparison) { 
    $0.0 == $1.0 && Int($0.1) == $1.1 
} 

за исключением того, , в ярости, функция equal, которая берет предикат, по-прежнему требует, чтобы элементы двух последовательностей были одинаковыми! Радар 17590938.

Быстрое исправление для этого конкретных массивов может выглядеть следующим образом:

func equal<T,U>(lhs: [T], rhs: [U], isEquivalent: (T,U)->Bool) -> Bool { 
    if lhs.count != rhs.count { return false } 
    return !contains(zip(lhs, rhs)) { !isEquivalent($0) } 
} 
// now the above use of equal will compile and return the correct result 

P.S. Вы можете добавить проверку переполнения для UInt преобразования

+0

Ну хорошо, так что я подал свой первый отчет об ошибке , great :) rdar: // 21096510 – ctietze

2

В поддержку @Airspeed скорости, кажется, ошибка, так как вы можете определить только первый кортеж, чем второй будет работать как: -/ Xcode 6.3. 2 Swift 1.2

let expectation: [(String, UInt)] = [("bar", 0)] 
let comparison: [(String, Int)] = [("foo", 1)] 

func ==(lhs: [(String, UInt)], rhs: [(String, Int)]) -> Bool { 
    if lhs.count != rhs.count { 
     return false 
    } 

    for ((l0, l1), r) in zip(lhs, rhs) { 
     // Explicitly detiled first tuple 
     if l0 != r.0 || Int(l1) != r.1 { 
      return false 
     } 
    } 

    return true 
} 

let equals = (expectation == comparison) // false as expected 
+0

Да, я убедил, что это ошибка. busted in 6.4 too –

1

Да, похоже на ошибку. Жутко, хотя, если заменить цикл с содержит(), вам не нужно разобрать кортеж, и она работает, как и следовало ожидать:

func ==(lhs: [(String, UInt)], rhs: [(String, Int)]) -> Bool { 
    if lhs.count != rhs.count { 
    return false 
    } 

    return !contains(zip(lhs, rhs)) { 
    l, r in l.0 != r.0 || Int(l.1) != r.1 
    } 

} 
+0

Это выглядит очень гладко! – ctietze

+1

Если вы хотите получить действительно краткий, вы можете поместить все это в одно утверждение: 'return lhs.endIndex == rhs.endIndex &&! Contains (zip (lhs, rhs)) {$ 0.0! = $ 1.0 || Int ($ 0.1)! = $ 1.1} ', но это примерно половина скорости других опций. – oisdk

Смежные вопросы