code

신속한 배열 비교

codestyles 2020. 12. 8. 08:06
반응형

신속한 배열 비교


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

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 Strings에서 ==에 대한 나쁜 기억이 있습니다.

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

감사.


다음에 대해 약간 긴장하는 것이 옳습니다 ==.

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하여 각 위치의 값을 비교합니다. 비트 비교를 수행 하지 않고== 각 요소 쌍에 대해 연산자를 호출합니다 . ==, 요소에 대한 사용자 지정 작성 하면 호출됩니다.

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

이 문제는 전적으로 NeverEqual평등 연산자 의 잘못입니다 . 평등은 전이적이고 대칭 적이며 반사적이어야하며 이것은 반사적이지 않습니다 ( x == x거짓). 그러나 그것은 여전히 ​​당신을 알지 못합니다.

Swift 배열은 copy-on-write입니다. 따라서 쓰기시 var x = y실제로 배열의 복사본을 만들지 않고 x의 저장 버퍼 포인터를 y's에 가리 킵니다 . x또는 y나중에 변경되는 경우에만 버퍼의 복사본을 만들어 변경되지 않은 변수에 영향을주지 않습니다. 이는 배열이 값 유형처럼 작동하지만 여전히 성능을 발휘하는 데 중요합니다.

스위프트의 초기 버전에서는, 당신은 실제로 부를 수있는 ===배열에 (도 초기 버전에서 돌연변이 동작은 돌연변이 경우 비트 다른이 있었다 x, y또한 그것을 선언했다하더라도 바꿀 것 let- 그들은 그것을 변경할 수 있도록에서 사람을 흥분하는) .

다음 ===과 같은 트릭 을 사용 하여 배열에 대한 이전 동작을 재현 할 수 있습니다 .

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

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

==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

그래서 대답 :

  1. I think the performance is optimal for doing value (not reference) comparisons
  2. Yes, if you want to compare values
  3. Swift arrays are value type and not reference type. So the memory location is the same only if you compare it to itself (or use unsafe pointers)

It depends on how do you want to compare. For example: ["1", "2"] == ["1", "2"] // true but ["1", "2"] == ["2", "1"] // false

If you need that second case to also be true and are ok with ignoring repetitive values, you can do: Set(["1", "2"]) == Set(["2", "1"]) // true (use NSSet for Swift 2)


For compare arrays of custom objects we can use elementsEqual.

class Person {

    let ID: Int!
    let name: String!

    init(ID: Int, name: String) {

        self.ID = ID
        self.name = name
    }
}

let oldFolks = [Person(ID: 1, name: "Ann"), Person(ID: 2, name: "Tony")]
let newFolks = [Person(ID: 2, name: "Tony"), Person(ID: 4, name: "Alice")]

if oldFolks.elementsEqual(newFolks, by: { $0.ID == $1.ID }) {

    print("Same people in same order")

} else {

    print("Nope")
}

Arrays conform to Equatable in Swift 4.1, negating the caveats mentioned in previous answers. This is available in Xcode 9.3.

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

But just because they implemented == did not mean Array or Optional conformed to Equatable. Since these types can store non-equatable types, we needed to be able to express that they are equatable only when storing an equatable type.

This meant these == operators had a big limitation: they couldn’t be used two levels deep.

With conditional conformance, we can now fix this. It allows us to write that these types conform to Equatable—using the already-defined == operator—if the types they are based on are equatable.


If you have an array of custom objects, one has to be careful with the equality test, at least with Swift 4.1:
If the custom object is not a subclass of NSObject, the comparison uses the static func == (lhs: Nsobject, rhs: Nsobject) -> Bool, which has to be defined.
If it is a subclass of NSObject, it uses the func isEqual(_ object: Any?) -> Bool, which has to be overridden.

Please check the following code, and set breakpoints at all return statements.

class Object: Equatable {

    static func == (lhs: Object, rhs: Object) -> Bool {
        return true
    }
}

The following class inheritates Equatable from NSObject

class Nsobject: NSObject {

    static func == (lhs: Nsobject, rhs: Nsobject) -> Bool {
        return true
    }


    override func isEqual(_ object: Any?) -> Bool {
        return true
    }

}  

They can be compared with:

let nsObject1 = Nsobject()
let nsObject2 = Nsobject()
let nsObjectArray1 = [nsObject1]
let nsObjectArray2 = [nsObject2]
let _ = nsObjectArray1 == nsObjectArray2

let object1 = Object()
let object2 = Object()
let objectArray1 = [object1]
let objectArray2 = [object2]
let _ = objectArray1 == objectArray2

참고URL : https://stackoverflow.com/questions/27567736/compare-arrays-in-swift

반응형