2014-12-19 3 views
38

배열을 비교하는 방법을 이해하려고 시도합니다.신속한 배열 비교

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) 모든 요소가 같으면 true가 반환됩니까? Java 문자열에 ==을 기억하지 못합니다.

3) myArray1과 myArray2가 기술적으로 동일한 "메모리 위치"/ 포인터/등을 사용하는지 확인하는 방법이 있습니까? 나는 최적화가 작동하는 방법과 잠재적 인주의 사항을 이해 한 후입니다.

감사합니다.

+0

직접 포인터 비교는'=== ' – Anorak

+0

입니다. 작동하지 않습니다. === says -> [String]이 AnyObject를 따르지 않는다. –

+0

@Anorak'==='은 클래스에만 사용되며,'Array'는 구조체이다. – Kirsteins

답변

58

을 경우에만 동일? 스위프트 배열은 Equatable을 준수하지 않는,하지만 그들은 같은 표준 라이브러리에 정의 된 == 연산자가 수행

func ==<T : Equatable>(lhs: [T], rhs: [T]) -> Bool 

이 연산자는 각각의 위치에서 값을 비교, lhsrhs의 요소 루프를. 이 아니며 비트 비교를합니다. 각 요소 쌍에서 == 연산자를 호출합니다. 즉, 요소에 대해 사용자 정의 ==을 작성하면 해당 요소가 호출됩니다.

그러나 최적화가 포함되어 있습니다. 두 배열의 기본 버퍼가 같으면 신경 쓰지 않고 그냥 true를 반환합니다 (물론 동일한 요소를 포함하고 있습니다!).

이 문제는 전적으로 NeverEqual 항등 연산자의 결함입니다. 평등은 전이, 대칭 및 재귀이어야하며이 하나는 재귀가 아닙니다 (x == x이 거짓 임). 그러나 그것은 여전히 ​​당신을 잡을 수 있습니다.

스위프트 배열 복사 (copy-on-write)입니다 - 그래서 당신은 var x = y을 쓸 때 실제로 배열의 카피를 작성하지 않습니다, 그것은 단지의 x 'y에서의 저장 버퍼 포인터'를 가리 킵니다. 나중에 x 또는 y이 변이 된 경우에만 버퍼의 복사본을 만들어 변경되지 않은 변수가 영향을받지 않도록합니다. 배열이 값 유형처럼 동작하지만 여전히 성능을 발휘하려면 매우 중요합니다. 당신이 xy 또한이 let 선언했다하더라도 바꿀 것 돌연변이 경우 스위프트의 초기 버전에서

, 실제로 초기 버전도 배열에 ===을 (부를 수의 변이 동작은 조금 달랐다 - 어느 겁에 질린 사람들은 그것을 바꿨다.) 어떻게 할 그것은에 따라

let a = [1,2,3] 
var b = a 

a.withUnsafeBufferPointer { outer in 
    b.withUnsafeBufferPointer { inner in 
     println(inner.baseAddress == outer.baseAddress) 
    } 
} 
+2

눈을 맞추는 것보다 더 많은 것이 있습니다. '[1] == [1]'은'true'를 반환하지만'[[1]] == [[1]]'은'false'를 반환합니다. 조심해! – Pitarou

+4

아, 재미 있어요. 실제로 Swift 컴파일러의 버그 (이전에 Swift 팀이 확인한 버그) 때문에 컴파일되지 않아야합니다. 그것은'Array''=='연산자를 사용하지 않습니다. 배열이 일치하지 않아서 내 게시물에 준 정의와 일치하지 않기 때문에 될 수 없습니다. 대신 Swift는 배열 리터럴을 포인터로 암시 적으로 변환하고,'UnsafePointer'에 대한'=='이 사용되고 있습니다. 버그는, 이것은 연산자를 위해서만, 함수 호출을 위해서만 가져서는 안된다. (단지 const 배열을 더 쉽게 취할 필요가있는 C 함수를 호출하기 위해서이다.) –

+3

올바른 것입니다. 지금 [[1]] == [[1]]은 참을 반환합니다 (Swift 2.3). – PabloR

13

==은 Swift에서 Java의 equals()과 동일하며 값을 비교합니다.

===은 Swift에서 Java의 ==과 동일하며 참조를 비교합니다.

이 큼 쉽게 배열 콘텐츠 값을 비교할 수 있습니다 스위프트에서

:

["1", "2"] == ["1", "2"] 

을하지만 당신은 참조를 비교하려면이 작동하지 않습니다 :

var myArray1 = [NSString(string: "1")] 
var myArray2 = [NSString(string: "1")] 

myArray1[0] === myArray2[0] // false 
myArray1[0] == myArray2[0] // true 

그래서 답 :

  1. 성능이 최적이라고 생각합니다 (참고 자료가 아님) 비교
  2. 예, 값을 비교하려는 경우
  3. 스위프트 배열은 참조 유형이 아닌 값 유형입니다.

    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 
    

    이유 : 그래서 메모리 위치는 당신이 자신을 비교 (또는 안전하지 않은 포인터를 사용) 당신이 바로 ==에 대해 약간 긴장하는 것

+0

=== 작동하지 않습니다. 분명히 그랬던 것 같습니다. 다른 방법으로 할 수 있습니까? 플러스를 매우 큰 배열로 호출하면 무엇을 할 수 있습니까? 이 문서에 명시된대로 전체 배열을 복사 할 예정입니까? 오버 헤드처럼 보입니다. –

+1

'==='는 참조 유형에서만 작동합니다. 값 유형은 항상 그들에 대한 참조가 1 개 뿐이므로'==='는 그것들에 대해 이해가되지 않습니다. 배열은 모든 구조체와 마찬가지로 복사되도록 "고려"되지만 성능상의 이유로 후드 배열은 변형 될 때까지 복사되지 않습니다. – Kirsteins

+0

이유는'myArray1 == myArray2'는'NSObject'가'Equatable'을 따르고'- [equals :]'를 호출하여 테스트를 수행한다는 것입니다. –

4

을 :

당신은 좀 트릭 (매우 구현에 의존 의존-에되지 파고 및 조사를 괴롭히는 제외)이와 배열에 ===의 이전 동작을 재현 할 수 있습니다 비교하고 싶다. 예를 들어 : ["1", "2"] == ["1", "2"] // true 하지만 ["1", "2"] == ["2", "1"] // false

당신이 두 번째 경우도 사실 일 것을 필요로하고 반복적 인 값을 무시로 확인하는 경우, 당신은 할 수 있습니다 : Set(["1", "2"]) == Set(["2", "1"]) // true (스위프트 2 NSSet 사용)

1

배열 Swift 4.1에서 Equatable을 준수하여 이전 답변에서 언급 한 경고를 무효화합니다. Xcode 9.3에서 사용할 수 있습니다.

그러나 단지 ==가 구현 때문에

https://swift.org/blog/conditional-conformance/

Array 의미하지 않았거나 OptionalEquatable을 따른다. 이러한 유형에는 유형이 아닌 유형을 저장할 수 있으므로 동등한 유형을 저장할 때만 동등하다는 것을 표현할 수 있어야했습니다.

이 의미는이 == 연산자가 큰 제한이 있다는 것을 의미했습니다. 두 레벨을 사용할 수 없었습니다.

조건부 준수를 통해이를 수정할 수 있습니다. 이미 정의 된 == 연산자를 사용하여 이러한 유형이 Equatable (해당 유형이 동등한 경우)을 준수한다고 작성할 수 있습니다.