arrays - المصفوفات - نوع المصفوفه




قارن المصفوفات بسرعة (4)

أنت محق في أن تكون متوترًا قليلاً حول == :

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 هذا المشغل العناصر في lhs و lhs ، ويقارن القيم في كل موضع. إنه لا يقوم بإجراء مقارنة bitwise - فإنه يستدعي العامل == في كل زوج من العناصر. هذا يعني أنك إذا كتبت مخصصًا == للعنصر الخاص بك ، فسيتم الاتصال بك.

ولكنه يحتوي على تحسين - إذا كانت المخازن المؤقتة الأساسية للصفيفين واحدة ، لا تهتم ، فهي ترجع فقط (تحتوي على عناصر متطابقة ، بالطبع أنها متساوية!).

هذه المشكلة هي بالكامل خطأ مشغل المساواة NeverEqual . يجب أن تكون المساواة متعدية ومتماثلة وانعكاسية ، وهذا غير انعكاسي ( x == x غير صحيح). ولكن لا يزال من الممكن أن يلفت انتباهك.

تكون المصفوفات السريعة عبارة عن نسخ عند الكتابة - لذلك عندما تكتب var x = y فإنها لا تنشئ بالفعل نسخة من المصفوفة ، فهي تشير فقط إلى مؤشر التخزين المؤقت لـ x في y . فقط إذا تم تغيير 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) 
    } 
}

محاولة لفهم كيف يقارن سريع صفائف.

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) هل نحن على يقين من أن == سوف يعود حقيقيًا إذا كانت جميع العناصر متساوية؟ لدي ذكريات سيئة من == على سلاسل جافا

3) هل هناك طريقة للتحقق مما إذا كان myArray1 و myArray2 يستخدمان تقنيًا نفس "موقع الذاكرة" / المؤشر / إلخ؟ أنا بعد فهم كيفية عمل التحسين والمحاذير المحتملة.

شكر.


إذا كان لديك مجموعة من الكائنات المخصصة ، فيجب أن يكون المرء حذرًا في اختبار المساواة ، على الأقل مع Swift 4.1:
إذا كان الكائن المخصص ليس فئة فرعية من NSObject ، فإن المقارنة تستخدم static func == (lhs: Nsobject, rhs: Nsobject) -> Bool ، والتي يجب تعريفها.
إذا كانت فئة فرعية من NSObject ، فإنها تستخدم func isEqual(_ object: Any?) -> Bool ، والتي يجب تجاوزها.

يرجى التحقق من الكود التالي ، وتعيين نقاط التوقف في جميع عبارات الإرجاع.

class Object: Equatable {

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

يرث الفصل التالي Equatable من NSObject

class Nsobject: NSObject {

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


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

}  

يمكن مقارنتها بـ:

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

ذلك يعتمد على كيف تريد المقارنة. على سبيل المثال: ["1", "2"] == ["1", "2"] // true لكن ["1", "2"] == ["2", "1"] // false

إذا كنت بحاجة إلى أن تكون هذه الحالة الثانية صحيحة أيضًا وتوافق على تجاهل القيم المتكررة ، يمكنك القيام بذلك: Set(["1", "2"]) == Set(["2", "1"]) // true (استخدم NSSet لـ Swift 2)


لمقارنة صفائف الكائنات المخصصة ، يمكننا استخدام 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")
}






comparison