การรับวัตถุจาก NSSet


คำตอบ:


140

มีหลายกรณีการใช้งานสำหรับชุด คุณสามารถระบุถึง (เช่นกับenumerateObjectsUsingBlockหรือ NSFastEnumeration) โทรcontainsObjectไปทดสอบสำหรับสมาชิกใช้งานanyObjectที่จะได้รับเป็นสมาชิก (ไม่สุ่ม) หรือแปลงเป็นอาร์เรย์ (โดยเฉพาะเพื่อไม่) allObjectsด้วย

ชุดมีความเหมาะสมเมื่อคุณไม่ต้องการซ้ำไม่สนใจคำสั่งซื้อและต้องการการทดสอบการเป็นสมาชิกที่รวดเร็ว


7
คุณยังสามารถค้นหาวัตถุที่เป็นที่รู้จักโดยอาจเกิดรายการซ้ำได้โดยการส่งชุดmember:ข้อความ หากส่งคืนnilชุดจะไม่มีวัตถุเท่ากับวัตถุที่คุณส่งผ่าน ถ้ามันส่งคืนตัวชี้วัตถุตัวชี้ที่ส่งกลับมาคือวัตถุที่อยู่ในชุดแล้ว อ็อบเจ็กต์ในชุดต้องใช้hashและisEqual:เพื่อให้เป็นประโยชน์
Peter Hosey

@PeterHosey ฉันไม่คิดว่าhash ความต้องการที่จะดำเนินการ; มันจะเร็วขึ้นมากถ้าคุณทำอย่างนั้น
fumoboy007

2
@ fumoboy007: สำหรับการจัดเก็บในชุดหรือใช้เป็นคีย์ในพจนานุกรมใช่เลย จากเอกสารของhashในโปรโตคอล NSObject:“ ถ้าวัตถุสองชิ้นเท่ากัน (ตามที่กำหนดโดยisEqual:วิธีการ) วัตถุเหล่านั้นจะต้องมีค่าแฮชเท่ากัน” ขณะนี้การดำเนินการของ NSObject hashและisEqual:ใช้ข้อมูลประจำตัวของวัตถุ (ที่อยู่) หากคุณลบล้างisEqual:คุณกำลังตั้งค่าความเป็นไปได้ของอ็อบเจ็กต์ที่ไม่เหมือนกัน แต่มีค่าเท่ากันซึ่งหากคุณไม่ลบล้างhashก็จะยังคงมีแฮชที่แตกต่างกัน นั่นเป็นการละเมิดข้อกำหนดที่ให้วัตถุที่เท่ากันมีแฮชเท่ากัน
Peter Hosey

1
@ fumoboy007: พิจารณาว่าตารางแฮชทำงานอย่างไร: คอนเทนเนอร์มีอาร์เรย์ของที่เก็บข้อมูลจำนวนหนึ่งและใช้แฮชของวัตถุที่เข้ามาแต่ละรายการเพื่อพิจารณาว่าควรอยู่ในที่เก็บข้อมูลใดสำหรับการค้นหาเช่นmember:คอนเทนเนอร์จะดูเฉพาะในที่เก็บข้อมูลนั้น ที่เก็บข้อมูล (ด้วยเหตุนี้ชุดจึงเร็วกว่าอาร์เรย์ในการทดสอบการเป็นสมาชิกและพจนานุกรมจึงเร็วกว่าอาร์เรย์แบบขนานในการค้นหาคีย์ - ค่า) หากวัตถุที่ค้นหามีแฮชที่ไม่ถูกต้องคอนเทนเนอร์จะดูในถังที่ไม่ถูกต้องและไม่พบสิ่งที่ตรงกัน
Peter Hosey

@PeterHosey อ๊ะ…ฉันเข้าใจผิดคิดว่าการใช้งานเริ่มต้น-[NSObject hash]คือ 0 ซึ่งอธิบายได้มาก = S
fumoboy007

31

NSSet ไม่มีเมธอด objectAtIndex:

ลองเรียก allObjects ซึ่งส่งคืน NSArray ของวัตถุทั้งหมด


คุณมีความคิดหรือไม่ว่าอาร์เรย์ที่ส่งคืนถูกสั่งซื้อหรือไม่? กล่าวอีกนัยหนึ่งถ้าฉันเพิ่มวัตถุในชุดโดยใช้ "setByAddingObject" และฉันใช้ "allObjects" คือ? องค์ประกอบในอาร์เรย์เรียงตามลำดับที่ฉันเพิ่มวัตถุ?
iosMentalist

เพียงจัดเรียงอาร์เรย์ผลลัพธ์ด้วย NSSortPredicate แล้วคุณจะสบายดี
Jason

หากคุณสนใจเฉพาะออบเจ็กต์เดียวให้ใช้วิธี filteredSetUsingPredicate ดีกว่า
ส.ค.

17

เป็นไปได้ที่จะใช้ filteredSetUsingPredicate หากคุณมีตัวระบุเฉพาะบางประเภทเพื่อเลือกวัตถุที่คุณต้องการ

ขั้นแรกให้สร้างเพรดิเคต (สมมติว่า id เฉพาะของคุณในออบเจ็กต์เรียกว่า "ตัวระบุ" และเป็น NSString):

NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];

จากนั้นเลือกวัตถุโดยใช้เพรดิเคต:

NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;

13

NSArray *myArray = [myNSSet allObjects];

MyObject *object = [myArray objectAtIndex:(NSUInteger *)]

แทนที่ NSUInteger ด้วยดัชนีของวัตถุที่คุณต้องการ


1
ควรเป็น: MyObject * object = [myArray objectAtIndex: (NSUInteger *)]
John D.


6

NSSet ใช้เมธอด isEqual: (ซึ่งอ็อบเจ็กต์ที่คุณใส่ลงในเซ็ตนั้นต้องลบล้างนอกจากนี้วิธีแฮช) เพื่อตรวจสอบว่าอ็อบเจ็กต์อยู่ภายในหรือไม่

ตัวอย่างเช่นหากคุณมีโมเดลข้อมูลที่กำหนดความเป็นเอกลักษณ์ด้วยค่า id (บอกว่าคุณสมบัติคือ:

@property NSUInteger objectID;

จากนั้นคุณจะใช้ isEqual: as

- (BOOL)isEqual:(id)object
{
  return (self.objectID == [object objectID]);
}

และคุณสามารถใช้แฮช:

- (NSUInteger)hash
{
 return self.objectID;  // to be honest, I just do what Apple tells me to here
                       // because I've forgotten how Sets are implemented under the hood
}

จากนั้นคุณจะได้รับวัตถุที่มี ID นั้น (รวมทั้งตรวจสอบว่าอยู่ใน NSSet หรือไม่) ด้วย:

MyObject *testObject = [[MyObject alloc] init];
testObject.objectID = 5; // for example.  

// I presume your object has more properties which you don't need to set here 
// because it's objectID that defines uniqueness (see isEqual: above)

MyObject *existingObject = [mySet member: testObject];

// now you've either got it or existingObject is nil

แต่ใช่วิธีเดียวที่จะนำบางสิ่งออกจาก NSSet คือการพิจารณาสิ่งที่กำหนดความเป็นเอกลักษณ์ตั้งแต่แรก

ฉันยังไม่ได้ทดสอบว่าอะไรเร็วกว่า แต่ฉันหลีกเลี่ยงการใช้การแจงนับเพราะอาจเป็นเส้นตรงในขณะที่การใช้เมมเบอร์: เมธอดจะเร็วกว่ามาก นั่นเป็นหนึ่งในเหตุผลที่ชอบใช้ NSSet แทน NSArray



0

เวลาส่วนใหญ่คุณไม่สนใจที่จะรับวัตถุชิ้นใดชิ้นหนึ่งจากชุด คุณสนใจเกี่ยวกับการทดสอบเพื่อดูว่าชุดนั้นมีวัตถุหรือไม่ นั่นคือสิ่งที่ดีสำหรับชุด เมื่อคุณต้องการดูว่าวัตถุที่อยู่ในชุดคอลเลกชันนั้นเร็วกว่าอาร์เรย์มากหรือไม่

หากคุณไม่สนใจว่าจะได้ของชิ้นไหนมาให้ใช้-anyObjectแค่วัตถุชิ้นเดียวจากชุดเช่นเอามือใส่กระเป๋าแล้วหยิบของ

Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects

หากคุณสนใจเกี่ยวกับวัตถุที่คุณได้รับให้ใช้-memberวัตถุที่ให้วัตถุกลับคืนมาหรือไม่มีหากไม่มีอยู่ในชุด คุณต้องมีวัตถุอยู่แล้วก่อนที่จะเรียกใช้

Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above

นี่คือรหัสบางส่วนที่คุณสามารถเรียกใช้ใน Xcode เพื่อทำความเข้าใจเพิ่มเติม

NSString *one = @"One";
NSString *two = @"Two";
NSString *three = @"Three";

NSSet *set = [NSSet setWithObjects:one, two, three, nil];

// Can't use Objective-C literals to create a set.
// Incompatible pointer types initializing 'NSSet *' with an expression of type 'NSArray *'
//  NSSet *set = @[one, two, three];

NSLog(@"Set: %@", set);
// Prints looking just like an array but is actually not in any order
//Set: {(
//     One,
//     Two,
//     Three
//     )}

// Get a random object
NSString *random = [set anyObject];
NSLog(@"Random: %@", random); // Random: One

// Iterate through objects. Again, although it prints in order, the order is a lie
for (NSString *aString in set) {
    NSLog(@"A String: %@", aString);
}

// Get an array from the set
NSArray *array = [set allObjects];
NSLog(@"Array: %@", array);

// Check for an object
if ([set containsObject:two]) {
    NSLog(@"Set contains two");
}

// Check whether a set contains an object and return that object if it does (nil if not)
NSString *aTwo = [set member:two];
if (aTwo) {
    NSLog(@"Set contains: %@", aTwo);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.