Swift Language
Массивы
Поиск…
Вступление
Синтаксис
- Array <Element> // Тип массива с элементами типа Element
- [Элемент] // Синтаксический сахар для типа массива с элементами типа Element
- [element0, element1, element2, ... elementN] // Литерал массива
- [Element] () // Создает новый пустой массив типа [Element]
- Array (count: repeatValue :) // Создает массив элементов
count
, каждый из которых инициализируетсяrepeatedValue
- Array (_ :) // Создает массив из произвольной последовательности
замечания
Массивы представляют собой упорядоченный набор значений. Значения могут повторяться, но должны быть одного типа.
Ценностная семантика
Копирование массива копирует все элементы внутри исходного массива.
Изменение нового массива не изменит исходный массив.
var originalArray = ["Swift", "is", "great!"]
var newArray = originalArray
newArray[2] = "awesome!"
//originalArray = ["Swift", "is", "great!"]
//newArray = ["Swift", "is", "awesome!"]
Скопированные массивы будут использовать то же пространство в памяти, что и оригинал, до тех пор, пока они не будут изменены. В результате этого происходит поражение производительности, когда скопированному массиву присваивается собственное пространство в памяти, поскольку оно изменяется впервые.
Основы массивов
Array
- это упорядоченный тип коллекции в стандартной библиотеке Swift. Он обеспечивает O (1) случайный доступ и динамическое перераспределение. Массив - это общий тип , поэтому тип значений, которые он содержит, известен во время компиляции.
Поскольку Array
является типом значения , его изменчивость определяется тем, является ли он аннотированным как var
(mutable) или let
(immutable).
Тип [Int]
(значение: массив, содержащий Int
s) является синтаксическим сахаром для Array<T>
.
Узнайте больше о массивах на языке Swift Programming .
Пустые массивы
Следующие три объявления эквивалентны:
// A mutable array of Strings, initially empty.
var arrayOfStrings: [String] = [] // type annotation + array literal
var arrayOfStrings = [String]() // invoking the [String] initializer
var arrayOfStrings = Array<String>() // without syntactic sugar
Литералы массива
Литерал массива записывается с квадратными скобками, окружающими элементы, разделенные запятыми:
// Create an immutable array of type [Int] containing 2, 4, and 7
let arrayOfInts = [2, 4, 7]
Компилятор обычно может вывести тип массива на основе элементов в литерале, но явные аннотации типов могут переопределять значение по умолчанию:
let arrayOfUInt8s: [UInt8] = [2, 4, 7] // type annotation on the variable
let arrayOfUInt8s = [2, 4, 7] as [UInt8] // type annotation on the initializer expression
let arrayOfUInt8s = [2 as UInt8, 4, 7] // explicit for one element, inferred for the others
Массивы с повторяющимися значениями
// An immutable array of type [String], containing ["Example", "Example", "Example"]
let arrayOfStrings = Array(repeating: "Example",count: 3)
Создание массивов из других последовательностей
let dictionary = ["foo" : 4, "bar" : 6]
// An immutable array of type [(String, Int)], containing [("bar", 6), ("foo", 4)]
let arrayOfKeyValuePairs = Array(dictionary)
Многомерные массивы
В Swift многомерный массив создается массивами вложенности: двумерный массив Int
- [[Int]]
(или Array<Array<Int>>
).
let array2x3 = [
[1, 2, 3],
[4, 5, 6]
]
// array2x3[0][1] is 2, and array2x3[1][2] is 6.
Чтобы создать многомерный массив повторяющихся значений, используйте вложенные вызовы инициализатора массива:
var array3x4x5 = Array(repeating: Array(repeating: Array(repeating: 0,count: 5),count: 4),count: 3)
Доступ к значениям массива
Следующие примеры будут использовать этот массив для демонстрации доступа к значениям
var exampleArray:[Int] = [1,2,3,4,5]
//exampleArray = [1, 2, 3, 4, 5]
Чтобы получить доступ к значению в известном индексе, используйте следующий синтаксис:
let exampleOne = exampleArray[2]
//exampleOne = 3
Примечание . Значение в индексе два является третьим значением в Array
. Array
s использует индекс на основе нуля, что означает, что первый элемент в Array
имеет индекс 0.
let value0 = exampleArray[0]
let value1 = exampleArray[1]
let value2 = exampleArray[2]
let value3 = exampleArray[3]
let value4 = exampleArray[4]
//value0 = 1
//value1 = 2
//value2 = 3
//value3 = 4
//value4 = 5
Доступ к подмножеству Array
с использованием фильтра:
var filteredArray = exampleArray.filter({ $0 < 4 })
//filteredArray = [1, 2, 3]
Фильтры могут иметь сложные условия, такие как фильтрация только четных чисел:
var evenArray = exampleArray.filter({ $0 % 2 == 0 })
//evenArray = [2, 4]
Также можно вернуть индекс заданного значения, возвращая nil
если значение не было найдено.
exampleArray.indexOf(3) // Optional(2)
Существуют методы для первого, последнего, максимального или минимального значения в Array
. Эти методы возвратят nil
если Array
пуст.
exampleArray.first // Optional(1)
exampleArray.last // Optional(5)
exampleArray.maxElement() // Optional(5)
exampleArray.minElement() // Optional(1)
Полезные методы
Определить, пуст ли массив или вернуть его размер
var exampleArray = [1,2,3,4,5]
exampleArray.isEmpty //false
exampleArray.count //5
Reverse a Array Примечание. Результат не выполняется в массиве, на который вызывается метод, и должен быть помещен в его собственную переменную.
exampleArray = exampleArray.reverse()
//exampleArray = [9, 8, 7, 6, 5, 3, 2]
Изменение значений в массиве
Существует несколько способов добавления значений в массив
var exampleArray = [1,2,3,4,5]
exampleArray.append(6)
//exampleArray = [1, 2, 3, 4, 5, 6]
var sixOnwards = [7,8,9,10]
exampleArray += sixOnwards
//exampleArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
и удалить значения из массива
exampleArray.removeAtIndex(3)
//exampleArray = [1, 2, 3, 5, 6, 7, 8, 9, 10]
exampleArray.removeLast()
//exampleArray = [1, 2, 3, 5, 6, 7, 8, 9]
exampleArray.removeFirst()
//exampleArray = [2, 3, 5, 6, 7, 8, 9]
Сортировка массива
var array = [3, 2, 1]
Создание нового отсортированного массива
Поскольку Array
соответствует SequenceType
, мы можем создать новый массив отсортированных элементов, используя встроенный метод сортировки.
В Swift 2 это делается с помощью метода sort()
.
let sorted = array.sort() // [1, 2, 3]
С Swift 3 он был переименован в sorted()
.
let sorted = array.sorted() // [1, 2, 3]
Сортировка существующего массива на месте
Поскольку Array
соответствует MutableCollectionType
, мы можем сортировать его элементы на месте.
В Swift 2 это выполняется с помощью sortInPlace()
.
array.sortInPlace() // [1, 2, 3]
С Swift 3 он был переименован в sort()
.
array.sort() // [1, 2, 3]
Примечание. Чтобы использовать вышеуказанные методы, элементы должны соответствовать протоколу
Comparable
.
Сортировка массива с пользовательским заказом
Вы также можете отсортировать массив, используя закрытие, чтобы определить, должен ли один элемент быть заказан другим, - который не ограничивается массивами, где элементы должны быть Comparable
. Например, для Landmark
не Comparable
но вы все равно можете отсортировать массив ориентиров по высоте или имени.
struct Landmark {
let name : String
let metersTall : Int
}
var landmarks = [Landmark(name: "Empire State Building", metersTall: 443),
Landmark(name: "Eifell Tower", metersTall: 300),
Landmark(name: "The Shard", metersTall: 310)]
// sort landmarks by height (ascending)
landmarks.sortInPlace {$0.metersTall < $1.metersTall}
print(landmarks) // [Landmark(name: "Eifell Tower", metersTall: 300), Landmark(name: "The Shard", metersTall: 310), Landmark(name: "Empire State Building", metersTall: 443)]
// create new array of landmarks sorted by name
let alphabeticalLandmarks = landmarks.sort {$0.name < $1.name}
print(alphabeticalLandmarks) // [Landmark(name: "Eifell Tower", metersTall: 300), Landmark(name: "Empire State Building", metersTall: 443), Landmark(name: "The Shard", metersTall: 310)]
// sort landmarks by height (ascending)
landmarks.sort {$0.metersTall < $1.metersTall}
// create new array of landmarks sorted by name
let alphabeticalLandmarks = landmarks.sorted {$0.name < $1.name}
Примечание. Сравнение строк может дать неожиданные результаты, если строки непоследовательны, см. Раздел Сортировка массива строк .
Преобразование элементов массива с помощью карты (_ :)
Поскольку Array
соответствует SequenceType
, мы можем использовать map(_:)
для преобразования массива A
в массив из B
используя замыкание типа (A) throws -> B
Например, мы могли бы использовать его для преобразования массива Int
s в массив String
s следующим образом:
let numbers = [1, 2, 3, 4, 5]
let words = numbers.map { String($0) }
print(words) // ["1", "2", "3", "4", "5"]
map(_:)
будет проходить через массив, применяя данное замыкание к каждому элементу. Результат этого закрытия будет использован для заполнения нового массива преобразованными элементами.
Поскольку String
имеет инициализатор, который получает Int
мы также можем использовать этот более четкий синтаксис:
let words = numbers.map(String.init)
Преобразование map(_:)
не должно изменять тип массива - например, оно также может использоваться для умножения массива Int
s на два:
let numbers = [1, 2, 3, 4, 5]
let numbersTimes2 = numbers.map {$0 * 2}
print(numbersTimes2) // [2, 4, 6, 8, 10]
Извлечение значений данного типа из массива с помощью flatMap (_ :)
things
Array содержат значения Any
типа.
let things: [Any] = [1, "Hello", 2, true, false, "World", 3]
Мы можем извлечь значения данного типа и создать новый массив этого конкретного типа. Предположим, мы хотим извлечь все Int(s)
и поместить их в Int
Array безопасным способом.
let numbers = things.flatMap { $0 as? Int }
Теперь numbers
определяются как [Int]
. Функция flatMap
отбрасывает все элементы nil
и результат, таким образом, содержит только следующие значения:
[1, 2, 3]
Фильтрация массива
Вы можете использовать метод filter(_:)
для SequenceType
, чтобы создать новый массив, содержащий элементы последовательности, которые удовлетворяют заданному предикату, который может быть предоставлен как закрытие .
Например, фильтрация четных чисел из [Int]
:
let numbers = [22, 41, 23, 30]
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers) // [22, 30]
Фильтрация [Person]
, где их возраст меньше 30:
struct Person {
var age : Int
}
let people = [Person(age: 22), Person(age: 41), Person(age: 23), Person(age: 30)]
let peopleYoungerThan30 = people.filter { $0.age < 30 }
print(peopleYoungerThan30) // [Person(age: 22), Person(age: 23)]
Фильтрация нуля из преобразования массива с помощью flatMap (_ :)
Вы можете использовать flatMap(_:)
аналогичным образом, чтобы map(_:)
, чтобы создать массив, применив преобразование к элементам последовательности.
extension SequenceType {
public func flatMap<T>(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]
}
Разница с этой версией flatMap(_:)
заключается в том, что она ожидает, что замыкание преобразования вернет необязательное значение T?
для каждого из элементов. Затем он безопасно разворачивает каждое из этих необязательных значений, отфильтровывая nil
- в результате получается массив из [T]
.
Например, вы можете это сделать, чтобы преобразовать [String]
в [Int]
используя инициализатор String
инициализирующий Int
, и отфильтровывать любые элементы, которые не могут быть преобразованы:
let strings = ["1", "foo", "3", "4", "bar", "6"]
let numbersThatCanBeConverted = strings.flatMap { Int($0) }
print(numbersThatCanBeConverted) // [1, 3, 4, 6]
Вы также можете использовать flatMap(_:)
, чтобы отфильтровать nil
, чтобы просто преобразовать массив необязательных элементов в массив не-опций:
let optionalNumbers : [Int?] = [nil, 1, nil, 2, nil, 3]
let numbers = optionalNumbers.flatMap { $0 }
print(numbers) // [1, 2, 3]
Подписывание массива с диапазоном
Можно выделить ряд последовательных элементов из массива с использованием диапазона.
let words = ["Hey", "Hello", "Bonjour", "Welcome", "Hi", "Hola"]
let range = 2...4
let slice = words[range] // ["Bonjour", "Welcome", "Hi"]
Subscripting Array с диапазоном возвращает ArraySlice
. Это подпоследовательность массива.
В нашем примере у нас есть массив строк, поэтому мы возвращаем ArraySlice<String>
.
Хотя ArraySlice соответствует CollectionType
и может использоваться с sort
, filter
и т. Д., Его назначение не для долговременного хранения, а для временных вычислений: оно должно быть преобразовано обратно в массив, как только вы закончите работать с ним.
Для этого используйте инициализатор Array()
:
let result = Array(slice)
Подводя итог на простом примере без промежуточных шагов:
let words = ["Hey", "Hello", "Bonjour", "Welcome", "Hi", "Hola"]
let selectedWords = Array(words[2...4]) // ["Bonjour", "Welcome", "Hi"]
Группировка значений массива
Если у нас есть такая структура
struct Box {
let name: String
let thingsInside: Int
}
и массив Box(es)
let boxes = [
Box(name: "Box 0", thingsInside: 1),
Box(name: "Box 1", thingsInside: 2),
Box(name: "Box 2", thingsInside: 3),
Box(name: "Box 3", thingsInside: 1),
Box(name: "Box 4", thingsInside: 2),
Box(name: "Box 5", thingsInside: 3),
Box(name: "Box 6", thingsInside: 1)
]
мы можем сгруппировать ящики с thingsInside
свойства thingsInside
, чтобы получить Dictionary
котором key
- это количество вещей, а значение - это массив ящиков.
let grouped = boxes.reduce([Int:[Box]]()) { (res, box) -> [Int:[Box]] in
var res = res
res[box.thingsInside] = (res[box.thingsInside] ?? []) + [box]
return res
}
Теперь сгруппировано [Int:[Box]]
и имеет следующий контент
[
2: [Box(name: "Box 1", thingsInside: 2), Box(name: "Box 4", thingsInside: 2)],
3: [Box(name: "Box 2", thingsInside: 3), Box(name: "Box 5", thingsInside: 3)],
1: [Box(name: "Box 0", thingsInside: 1), Box(name: "Box 3", thingsInside: 1), Box(name: "Box 6", thingsInside: 1)]
]
Сглаживание результата преобразования массива с помощью flatMap (_ :)
Помимо возможности создания массива путем фильтрации nil
из преобразованных элементов последовательности, существует также версия flatMap(_:)
которая ожидает, что замыкание преобразования вернет последовательность S
extension SequenceType {
public func flatMap<S : SequenceType>(transform: (Self.Generator.Element) throws -> S) rethrows -> [S.Generator.Element]
}
Каждая последовательность из преобразования будет конкатенирована, в результате получается массив, содержащий объединенные элементы каждой последовательности - [S.Generator.Element]
.
Объединение символов в массив строк
Например, мы можем использовать его, чтобы взять массив простых строк и объединить их символы в один массив:
let primes = ["2", "3", "5", "7", "11", "13", "17", "19"]
let allCharacters = primes.flatMap { $0.characters }
// => "["2", "3", "5", "7", "1", "1", "1", "3", "1", "7", "1", "9"]"
Прерывая приведенный выше пример:
-
primes
-[String]
(Поскольку массив представляет собой последовательность, мы можем вызватьflatMap(_:)
на нем). - Закрытие преобразования принимает один из элементов
primes
,String
(Array<String>.Generator.Element
). - Затем замыкание возвращает последовательность типа
String.CharacterView
. - Результатом является массив, содержащий объединенные элементы всех последовательностей от каждого из вызовов замыкания трансформации -
[String.CharacterView.Generator.Element]
.
Сглаживание многомерного массива
Поскольку flatMap(_:)
будет конкатенировать последовательности, возвращаемые из вызовов замыкания преобразования, его можно использовать для выравнивания многомерного массива, такого как 2D-массив, в 1D-массив, трехмерный массив в 2D-массив и т. Д.
Это можно просто сделать, возвратив данный элемент $0
(вложенный массив) в замыкание:
// A 2D array of type [[Int]]
let array2D = [[1, 3], [4], [6, 8, 10], [11]]
// A 1D array of type [Int]
let flattenedArray = array2D.flatMap { $0 }
print(flattenedArray) // [1, 3, 4, 6, 8, 10, 11]
Сортировка массива строк
Самый простой способ - использовать sorted()
:
let words = ["Hello", "Bonjour", "Salute", "Ahola"]
let sortedWords = words.sorted()
print(sortedWords) // ["Ahola", "Bonjour", "Hello", "Salute"]
или sort()
var mutableWords = ["Hello", "Bonjour", "Salute", "Ahola"]
mutableWords.sort()
print(mutableWords) // ["Ahola", "Bonjour", "Hello", "Salute"]
Вы можете передать закрытие в качестве аргумента для сортировки:
let words = ["Hello", "Bonjour", "Salute", "Ahola"]
let sortedWords = words.sorted(isOrderedBefore: { $0 > $1 })
print(sortedWords) // ["Salute", "Hello", "Bonjour", "Ahola"]
Альтернативный синтаксис с закрывающейся крышкой:
let words = ["Hello", "Bonjour", "Salute", "Ahola"]
let sortedWords = words.sorted() { $0 > $1 }
print(sortedWords) // ["Salute", "Hello", "Bonjour", "Ahola"]
Но будут неожиданные результаты, если элементы в массиве несовместимы:
let words = ["Hello", "bonjour", "Salute", "ahola"]
let unexpected = words.sorted()
print(unexpected) // ["Hello", "Salute", "ahola", "bonjour"]
Чтобы решить эту проблему, выполните сортировку по строчной версии элементов:
let words = ["Hello", "bonjour", "Salute", "ahola"]
let sortedWords = words.sorted { $0.lowercased() < $1.lowercased() }
print(sortedWords) // ["ahola", "bonjour", "Hello", "Salute"]
Или import Foundation
и используйте методы сравнения NSString, такие как caseInsensitiveCompare
:
let words = ["Hello", "bonjour", "Salute", "ahola"]
let sortedWords = words.sorted { $0.caseInsensitiveCompare($1) == .orderedAscending }
print(sortedWords) // ["ahola", "bonjour", "Hello", "Salute"]
Кроме того, используйте localizedCaseInsensitiveCompare
, который может управлять диакритикой.
Чтобы правильно отсортировать строки по их числовому значению, используйте команду compare
с опцией .numeric
:
let files = ["File-42.txt", "File-01.txt", "File-5.txt", "File-007.txt", "File-10.txt"]
let sortedFiles = files.sorted() { $0.compare($1, options: .numeric) == .orderedAscending }
print(sortedFiles) // ["File-01.txt", "File-5.txt", "File-007.txt", "File-10.txt", "File-42.txt"]
Ленецкое сглаживание многомерного массива с плоским ()
Мы можем использовать flatten()
, чтобы лениво уменьшить вложенность многомерной последовательности.
Например, ленивое выравнивание 2D-массива в 1D-массив:
// A 2D array of type [[Int]]
let array2D = [[1, 3], [4], [6, 8, 10], [11]]
// A FlattenBidirectionalCollection<[[Int]]>
let lazilyFlattenedArray = array2D.flatten()
print(lazilyFlattenedArray.contains(4)) // true
В приведенном выше примере flatten()
вернет FlattenBidirectionalCollection
, который будет лениво применять сглаживание массива. Поэтому contains(_:)
будет требовать array2D
первых двух вложенных массивов array2D
поскольку он будет array2D
при поиске нужного элемента.
Объединение элементов массива с уменьшением (_: объединение :)
reduce(_:combine:)
можно использовать для объединения элементов последовательности в одно значение. Он принимает начальное значение для результата, а также замыкание, применяемое к каждому элементу, - которое вернет новое накопленное значение.
Например, мы можем использовать его для суммирования массива чисел:
let numbers = [2, 5, 7, 8, 10, 4]
let sum = numbers.reduce(0) {accumulator, element in
return accumulator + element
}
print(sum) // 36
Мы передаем 0
в начальное значение, так как это логическое начальное значение для суммирования. Если бы мы передали значение N
, то полученная sum
бы равна N + 36
. Закрытие, переданное для reduce
имеет два аргумента. accumulator
- это текущее накопленное значение, которому присваивается значение, возвращаемое замыканием на каждой итерации. element
- текущий элемент итерации.
Как и в этом примере, мы reduce
(Int, Int) -> Int
замыкание, которое просто выводит добавление двух входов - мы можем фактически передавать оператор +
непосредственно, поскольку операторы являются функциями в Swift:
let sum = numbers.reduce(0, combine: +)
Удаление элемента из массива без знания его индекса
Как правило, если мы хотим удалить элемент из массива, нам нужно знать его индекс, чтобы мы могли легко его remove(at:)
используя remove(at:)
function.
Но что, если мы не знаем индекс, но знаем значение элемента, который нужно удалить!
Итак, вот простое расширение массива, которое позволит нам легко удалить элемент из массива, не зная его индекса:
Swift3
extension Array where Element: Equatable {
mutating func remove(_ element: Element) {
_ = index(of: element).flatMap {
self.remove(at: $0)
}
}
}
например
var array = ["abc", "lmn", "pqr", "stu", "xyz"]
array.remove("lmn")
print("\(array)") //["abc", "pqr", "stu", "xyz"]
array.remove("nonexistent")
print("\(array)") //["abc", "pqr", "stu", "xyz"]
//if provided element value is not present, then it will do nothing!
Также, если по ошибке мы сделали что-то вроде этого: array.remove(25)
то есть мы предоставили значение с другим типом данных, компилятор будет вызывать ошибку,
cannot convert value to expected argument type
Поиск минимального или максимального элемента массива
Вы можете использовать minElement()
и maxElement()
чтобы найти минимальный или максимальный элемент в заданной последовательности. Например, с массивом чисел:
let numbers = [2, 6, 1, 25, 13, 7, 9]
let minimumNumber = numbers.minElement() // Optional(1)
let maximumNumber = numbers.maxElement() // Optional(25)
Возвращаемые значения из этих методов являются необязательными, чтобы отражать тот факт, что массив может быть пустым - если это так, возвращается nil
.
Примечание. Вышеупомянутые методы требуют, чтобы элементы соответствовали протоколу
Comparable
.
Поиск минимального или максимального элемента с пользовательским заказом
Вы также можете использовать вышеуказанные методы с пользовательским закрытием , определяя, должен ли один элемент быть заказан другим, позволяя вам найти минимальный или максимальный элемент в массиве, где элементы не обязательно Comparable
.
Например, с массивом векторов:
struct Vector2 {
let dx : Double
let dy : Double
var magnitude : Double {return sqrt(dx*dx+dy*dy)}
}
let vectors = [Vector2(dx: 3, dy: 2), Vector2(dx: 1, dy: 1), Vector2(dx: 2, dy: 2)]
// Vector2(dx: 1.0, dy: 1.0)
let lowestMagnitudeVec2 = vectors.minElement { $0.magnitude < $1.magnitude }
// Vector2(dx: 3.0, dy: 2.0)
let highestMagnitudeVec2 = vectors.maxElement { $0.magnitude < $1.magnitude }
let lowestMagnitudeVec2 = vectors.min { $0.magnitude < $1.magnitude }
let highestMagnitudeVec2 = vectors.max { $0.magnitude < $1.magnitude }
Безопасный доступ к индексам
Добавляя следующее расширение к индексам массива, можно получить доступ, не зная, находится ли индекс внутри границ.
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
пример:
if let thirdValue = array[safe: 2] {
print(thirdValue)
}
Сравнение 2 массивов с zip
Функция zip
принимает 2 параметра типа SequenceType
и возвращает Zip2Sequence
где каждый элемент содержит значение из первой последовательности и один из второй последовательности.
пример
let nums = [1, 2, 3]
let animals = ["Dog", "Cat", "Tiger"]
let numsAndAnimals = zip(nums, animals)
nomsAndAnimals теперь содержит следующие значения
sequence1 | sequence1 |
---|---|
1 | "Dog" |
2 | "Cat" |
3 | "Tiger" |
Это полезно, если вы хотите выполнить какое-то сравнение между n-м элементом каждого массива.
пример
Учитывая 2 массива Int(s)
let list0 = [0, 2, 4]
let list1 = [0, 4, 8]
вы хотите проверить, является ли каждое значение в list1
двойным из связанного значения в list0
.
let list1HasDoubleOfList0 = !zip(list0, list1).filter { $0 != (2 * $1)}.isEmpty