Сравнение массивов в быстрых
Попытка понять, как быстро сравнивает массивы.
var myArray1 : [String] = ["1","2","3","4","5"]
var myArray2 : [String] = ["1","2","3","4","5"]
// 1) Comparing 2 simple arrays
if(myArray1 == myArray2) {
println("Equality")
} else {
println("Equality no")
}
// -> prints equality -> thanks god
// 2) comparing to a "copy" of an array
// swift copies arrays when passed as parameters (as per doc)
func arrayTest(anArray: [String]) -> Bool {
return anArray == myArray1
}
println("Array test 1 is \(arrayTest(myArray1))")
println("Array test 2 is \(arrayTest(myArray2))")
// equality works for both
myArray2.append("test")
println("Array test 2 is \(arrayTest(myArray2))")
// false (obviously)
myArray2.removeAtIndex(5)
println("Array test 2 is \(arrayTest(myArray2))")
// true
Apple говорит, что за сценой есть исправления по копиям массива. Похоже, иногда - не всегда - структуры фактически копируются или нет.
Тем не менее,
1) является == итерированием по всему массиву для выполнения сравнения на основе элементов. (Похоже на то)
- > Как насчет использования производительности/памяти на очень больших массивах?
2) Мы уверены, что == когда-нибудь вернется, если все элементы равны? У меня плохие воспоминания о == на Java Strings
3) Есть ли способ проверить, являются ли myArray1 и myArray2 технически одним и тем же "местом памяти" /указателем/и т.д.? Я понимаю, как работает оптимизация и потенциальные оговорки.
Спасибо.
Ответы
Ответ 1
Вы можете слегка нервничать о ==
:
struct NeverEqual: Equatable { }
func ==(lhs: NeverEqual, rhs: NeverEqual)->Bool { return false }
let x = [NeverEqual()]
var y = x
x == y // this returns true
[NeverEqual()] == [NeverEqual()] // false
x == [NeverEqual()] // false
let z = [NeverEqual()]
x == z // false
x == y // true
y[0] = NeverEqual()
x == y // now false
Почему? Массивы Swift не соответствуют Equatable
, но они имеют оператор ==
, определенный в стандартной библиотеке как:
func ==<T : Equatable>(lhs: [T], rhs: [T]) -> Bool
Этот оператор пересекает элементы в lhs
и rhs
, сравнивая значения в каждой позиции. Он не выполняет побитовое сравнение - он вызывает оператор ==
для каждой пары элементов. Это означает, что если вы напишете пользовательский ==
для своего элемента, он будет вызван.
Но он содержит оптимизацию - если базовые буферы для двух массивов одинаковы, он не беспокоится, он просто возвращает true (они содержат одинаковые элементы, конечно же, равны!).
Эта проблема полностью является ошибкой оператора равенства NeverEqual
. Равенство должно быть транзитивным, симметричным и рефлексивным, а это не рефлексивным (x == x
является ложным). Но он все равно мог бы застать вас врасплох.
Быстрые массивы копируются при записи - поэтому, когда вы пишете var x = y
, он фактически не делает копию массива, он просто указывает указатель буфера хранения x
s на y
s. Только после того, как x
или y
будут мутированы, он сделает копию буфера, так что неизмененная переменная не будет затронута. Это очень важно для массивов, которые ведут себя как типы значений, но все же остаются работоспособными.
В ранних версиях Swift вы действительно могли называть ===
на массивах (также в ранних версиях, поведение мутирования было немного иным, если вы мутировали x
, y
также изменилось бы, даже если бы оно было объявленный с помощью let
- который искалечил людей, поэтому они изменили его).
Вы можете любопытно воспроизвести старое поведение ===
на массивах с этим (очень зависимое от реализации, не полагаться на него, за исключением трюков и подтасовки):
let a = [1,2,3]
var b = a
a.withUnsafeBufferPointer { outer in
b.withUnsafeBufferPointer { inner in
println(inner.baseAddress == outer.baseAddress)
}
}
Ответ 2
==
в Swift совпадает с Java equals()
, он сравнивает значения.
===
в Swift совпадает с Java ==
, он сравнивает ссылки.
В Swift вы можете сравнивать значения содержимого массива так же легко, как это:
["1", "2"] == ["1", "2"]
Но это не сработает, если вы хотите сравнить ссылки:
var myArray1 = [NSString(string: "1")]
var myArray2 = [NSString(string: "1")]
myArray1[0] === myArray2[0] // false
myArray1[0] == myArray2[0] // true
Итак, ответы:
- Я думаю, что производительность оптимальна для выполнения ценности (без ссылки)
сравнения
- Да, если вы хотите сравнить значения
- Массивы Swift - это тип значения, а не ссылочный тип. Итак, память
местоположение будет таким же, только если вы сравните его с собой (или используйте небезопасные
указатели)
Ответ 3
Это зависит от того, как вы хотите сравнить. Например:
["1", "2"] == ["1", "2"] // true
но
["1", "2"] == ["2", "1"] // false
Если вам нужен этот второй случай, чтобы он был истинным, и вы можете игнорировать повторяющиеся значения, вы можете сделать:
Set(["1", "2"]) == Set(["2", "1"]) // true
(используйте NSSet для Swift 2)