ฉันจะเรียงลำดับ NSMutableArray ด้วยวัตถุที่กำหนดเองได้อย่างไร


1268

สิ่งที่ฉันต้องการจะทำนั้นค่อนข้างง่าย แต่ฉันไม่สามารถหาคำตอบในเว็บได้ ฉันมีNSMutableArrayสิ่งของและสมมุติว่ามันเป็นวัตถุ 'บุคคล' ฉันต้องการที่จะเรียงลำดับNSMutableArrayโดย Person.birthDate NSDateซึ่งเป็น

ฉันคิดว่ามันเกี่ยวข้องกับวิธีการนี้:

NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(???)];

ใน Java ฉันจะทำให้วัตถุของฉันใช้ Comparable หรือใช้ Collections.sort กับเครื่องมือเปรียบเทียบแบบกำหนดเองแบบอินไลน์ ... คุณทำเช่นนี้ใน Objective-C อย่างไร

คำตอบ:


2299

เปรียบเทียบวิธีการ

ไม่ว่าคุณจะใช้วิธีการเปรียบเทียบสำหรับวัตถุของคุณ:

- (NSComparisonResult)compare:(Person *)otherObject {
    return [self.birthDate compare:otherObject.birthDate];
}

NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];

NSSortDescriptor (ดีกว่า)

หรือมักจะดีกว่า:

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                           ascending:YES];
NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];

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

บล็อก (เงา!)

นอกจากนี้ยังมีความเป็นไปได้ในการเรียงลำดับด้วยบล็อกตั้งแต่ Mac OS X 10.6 และ iOS 4:

NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    NSDate *first = [(Person*)a birthDate];
    NSDate *second = [(Person*)b birthDate];
    return [first compare:second];
}];

ประสิทธิภาพ

โดยทั่วไป-compare:แล้ววิธีการแบบบล็อกและแบบพื้นฐานนั้นจะเร็วกว่าการใช้NSSortDescriptorKVC เป็นอย่างน้อย ข้อได้เปรียบหลักของNSSortDescriptorวิธีนี้คือให้วิธีการกำหนดลำดับการจัดเรียงของคุณโดยใช้ข้อมูลแทนที่จะเป็นโค้ดซึ่งทำให้ง่ายต่อการตั้งค่าเพื่อให้ผู้ใช้สามารถเรียงลำดับได้NSTableViewโดยคลิกที่แถวส่วนหัว


66
ตัวอย่างแรกมีข้อบกพร่อง: คุณเปรียบเทียบตัวแปรอินสแตนซ์ของ birthDate ในวัตถุหนึ่งกับวัตถุอื่นเองแทนที่จะเป็นตัวแปร birthDate
Martin Gjaldbaek

90
@ มาร์ติน: ขอบคุณ! ตลกที่ไม่มีใครสังเกตเห็นก่อนที่ฉันจะได้ 75 upvotes สำหรับมัน
Georg Schölly

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

6
@ orange80: ฉันลองแล้ว ฉันไม่ได้เป็นเจ้าของ Mac อีกต่อไปดังนั้นจะดีถ้าคุณสามารถดูรหัสได้
Georg Schölly

11
หากคุณมีNSMutableArrayฉันชอบที่จะใช้ methodes sortUsingDescriptors, หรือsortUsingFunction sortUsingSelectorเท่าที่อาร์เรย์ไม่แน่นอนฉันมักจะไม่ต้องการคัดลอกเรียง
เตฟาน

109

ดูNSMutableArrayวิธีการsortUsingFunction:context:

คุณจะต้องตั้งค่าฟังก์ชั่นการเปรียบเทียบที่ใช้สองวัตถุ (ชนิดPersonเนื่องจากคุณกำลังเปรียบเทียบสองPersonวัตถุ) และพารามิเตอร์บริบท

Personวัตถุทั้งสองเป็นเพียงกรณีของ วัตถุที่สามคือสตริงเช่น @ "birthDate"

ฟังก์ชั่นนี้กลับNSComparisonResult: มันกลับNSOrderedAscendingถ้า<PersonA.birthDate PersonB.birthDateมันจะกลับมาNSOrderedDescendingถ้า>PersonA.birthDate PersonB.birthDateในที่สุดก็จะกลับมาNSOrderedSameถ้า==PersonA.birthDatePersonB.birthDate

นี่คือ pseudocode หยาบ คุณจะต้องระบุความหมายของวันที่ว่า "น้อยลง", "มากขึ้น" หรือ "เท่ากัน" กับวันที่อื่น (เช่นการเปรียบเทียบวินาทีตั้งแต่กาลเวลาเป็นต้น):

NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {
  if ([firstPerson birthDate] < [secondPerson birthDate])
    return NSOrderedAscending;
  else if ([firstPerson birthDate] > [secondPerson birthDate])
    return NSOrderedDescending;
  else 
    return NSOrderedSame;
}

หากคุณต้องการอะไรที่กะทัดรัดกว่านี้คุณสามารถใช้ตัวดำเนินการประกอบไปด้วย:

NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {
  return ([firstPerson birthDate] < [secondPerson birthDate]) ? NSOrderedAscending : ([firstPerson birthDate] > [secondPerson birthDate]) ? NSOrderedDescending : NSOrderedSame;
}

การอินไลน์อาจจะช่วยเร่งความเร็วขึ้นเล็กน้อยถ้าคุณทำสิ่งนี้มาก


9
การใช้ sortUsingFunction: context: น่าจะเป็นวิธีที่ดีที่สุดและแน่นอนที่สุดที่ไม่สามารถอ่านได้
Georg Schölly

12
ไม่มีอะไรผิดปกติกับมัน แต่ฉันคิดว่าตอนนี้มีทางเลือกที่ดีกว่ามาก
Georg Schölly

6
บางที แต่ฉันไม่คิดว่าจะมีคนที่อ่านพื้นหลัง Java ได้น้อยลงซึ่งอาจมองหาสิ่งที่คล้ายกับคลาส Comparator ของบทคัดย่อของ Java ซึ่งใช้การเปรียบเทียบ (Type obj1, Type obj2)
Alex Reynolds

5
ฉันรู้สึกว่าคุณสองคนกำลังมองหาเหตุผลใด ๆ ก็ตามที่จะวิพากษ์วิจารณ์คำตอบที่ดีอย่างสมบูรณ์แบบนี้แม้ว่าการวิจารณ์นั้นมีข้อดีทางเทคนิคน้อยมาก แปลก.
Alex Reynolds

1
@Yar: คุณสามารถใช้โซลูชันที่ฉันให้ไว้ในย่อหน้าแรกหรือคุณอาจใช้ตัวอธิบายการเรียงลำดับหลายตัวก็ได้ SortArrayUsingDescriptors:รับอาเรย์ของตัวเรียงลำดับการเรียงเป็นอาร์กิวเมนต์
Georg Schölly

62

ฉันทำสิ่งนี้ใน iOS 4 โดยใช้บล็อก ต้องหล่อองค์ประกอบของอาเรย์จาก id ไปยังประเภทคลาสของฉัน ในกรณีนี้มันเป็นคลาสที่เรียกว่าคะแนนพร้อมด้วยคุณสมบัติที่เรียกว่าคะแนน

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

NSArray *sorted = [_scores sortedArrayUsingComparator:^(id obj1, id obj2){
    if ([obj1 isKindOfClass:[Score class]] && [obj2 isKindOfClass:[Score class]]) {
        Score *s1 = obj1;
        Score *s2 = obj2;

        if (s1.points > s2.points) {
            return (NSComparisonResult)NSOrderedAscending;
        } else if (s1.points < s2.points) {
            return (NSComparisonResult)NSOrderedDescending;
        }
    }

    // TODO: default is the same?
    return (NSComparisonResult)NSOrderedSame;
}];

return sorted;

PS: นี่คือการเรียงลำดับจากมากไปน้อย


6
คุณไม่จำเป็นต้องใช้คำสั่ง "(คะแนน *)" ในนั้นคุณสามารถทำได้ "คะแนน * s1 = obj1;" เพราะ id จะถูกโยนอย่างมีความสุขกับทุกสิ่งโดยไม่มีการเตือนจากคอมไพเลอร์ :-)
jpswain

orange80 ที่ถูกdowncastingต้องไม่จำเป็นต้องใช้การร่ายก่อนตัวแปรอ่อนแอ
thesummersign

คุณควรเรียง nil vs. not-nil ให้อยู่ด้านบนหรือด้านล่างอย่างสม่ำเสมอดังนั้นการคืนค่าเริ่มต้นอาจเป็นไปได้return ((!obj1 && !obj2) ? NSOrderedSame : (obj1 ? NSOrderedAscending : NSOrderedDescending))
Scott Corscadden

Chris เฮ้ฉันลองใช้รหัสนี้ฉันทำ hv รีเฟรชในโปรแกรมของฉัน .. เป็นครั้งแรกที่ฉันทำงานที่ถูกต้องได้ผลลัพธ์เอาต์พุตที่ลดลง .. แต่เมื่อฉันรีเฟรช (รันรหัสเดียวกันกับข้อมูลเดียวกัน) มันเปลี่ยนไป คำสั่งมันไม่ได้ลดลง .. สมมติว่าฉัน hv 4 วัตถุในอาร์เรย์ของฉันข้อมูลเดียวกัน 3 hv, 1 แตกต่างกัน
Nikesh K

หากคุณคาดหวังว่าวัตถุที่ไม่ได้อยู่ในระดับ "คะแนน" คุณจะต้องเรียงลำดับวัตถุเหล่านี้อย่างระมัดระวังมากขึ้น มิฉะนั้นคุณจะมีสถานการณ์ที่อื่น ๆ == score1 <score2 == อื่น ๆ ที่ไม่สอดคล้องกันและอาจนำไปสู่ปัญหา คุณสามารถคืนค่าที่แสดงถึงการเรียงลำดับคะแนนวัตถุก่อนวัตถุอื่นทั้งหมดและวัตถุอื่น ๆ ทั้งหมดเรียงลำดับเท่ากับกัน
gnasher729

29

เริ่มต้นใน iOS 4 คุณยังสามารถใช้บล็อกเพื่อการเรียงลำดับ

สำหรับตัวอย่างนี้โดยเฉพาะอย่างยิ่งผมสมมติว่าวัตถุในอาร์เรย์ของคุณมี 'ตำแหน่ง' NSIntegerวิธีซึ่งส่งกลับ

NSArray *arrayToSort = where ever you get the array from... ;
NSComparisonResult (^sortBlock)(id, id) = ^(id obj1, id obj2) 
{
    if ([obj1 position] > [obj2 position]) 
    { 
        return (NSComparisonResult)NSOrderedDescending;
    }
    if ([obj1 position] < [obj2 position]) 
    {
        return (NSComparisonResult)NSOrderedAscending;
    }
    return (NSComparisonResult)NSOrderedSame;
};
NSArray *sorted = [arrayToSort sortedArrayUsingComparator:sortBlock];

หมายเหตุ: อาร์เรย์ "เรียงลำดับ" จะถูกลบอัตโนมัติ


26

ฉันพยายามทั้งหมด แต่สิ่งนี้ใช้ได้สำหรับฉัน ในชั้นเรียนฉันมีอีกชั้นหนึ่งชื่อ " crimeScene" และต้องการเรียงลำดับตามคุณสมบัติของ " crimeScene"

มันใช้งานได้เหมือนมนต์เสน่ห์:

NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"crimeScene.distance" ascending:YES];
[self.arrAnnotations sortUsingDescriptors:[NSArray arrayWithObject:sorter]];

21

มีขั้นตอนที่ขาดหายไปในคำตอบที่สองของ Georg Schöllyแต่ก็ใช้งานได้ดี

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                              ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];

// เพิ่ม 's' เพราะเวลาจะสูญเปล่าเมื่อฉันคัดลอกและวางและล้มเหลวโดยไม่มี 's' ใน sortArrayUsingDescriptors


การเรียกเมธอดนั้นเป็นจริง "sortArrayUsingDescriptors:" โดยมี 's' ที่ท้าย
CIFilter

19
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];

ขอบคุณมันทำงานได้ดี ...


17

Personวัตถุของคุณจำเป็นต้องใช้วิธีการบอกว่าcompare:จะใช้Personวัตถุอื่นและกลับมาNSComparisonResultตามความสัมพันธ์ระหว่างวัตถุ 2

จากนั้นคุณจะโทรsortedArrayUsingSelector:ด้วย@selector(compare:)และควรจะทำ

มีวิธีอื่น ๆ แต่เท่าที่ฉันรู้ว่าไม่มีComparableส่วนต่อประสานของ Cocoa-equiv การใช้sortedArrayUsingSelector:อาจเป็นวิธีที่เจ็บปวดที่สุดในการทำ


9

iOS 4 blocks จะช่วยคุณ :)

featuresArray = [[unsortedFeaturesArray sortedArrayUsingComparator: ^(id a, id b)  
{
    DMSeatFeature *first = ( DMSeatFeature* ) a;
    DMSeatFeature *second = ( DMSeatFeature* ) b;

    if ( first.quality == second.quality )
        return NSOrderedSame;
    else
    {
        if ( eSeatQualityGreen  == m_seatQuality || eSeatQualityYellowGreen == m_seatQuality || eSeatQualityDefault  == m_seatQuality )
        {
            if ( first.quality < second.quality )
                return NSOrderedAscending;
            else
                return NSOrderedDescending;
        }
        else // eSeatQualityRed || eSeatQualityYellow
        {
            if ( first.quality > second.quality )
                return NSOrderedAscending;
            else
                return NSOrderedDescending;
        } 
    }
}] retain];

http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.htmlคำอธิบายเล็กน้อย


8

สำหรับNSMutableArrayใช้sortUsingSelectorวิธีการ มันเรียงลำดับสถานที่โดยไม่ต้องสร้างอินสแตนซ์ใหม่


เพียงแค่การปรับปรุง: ฉันก็กำลังมองหาบางสิ่งบางอย่างที่เรียงแถวไม่แน่นอนในสถานที่ที่มีอยู่ในขณะนี้ "sortUsing" วิธีการที่เทียบเท่าสำหรับทุกคน "sortedArrayUsing" วิธีการเป็นของ iOS 7 sortUsingComparator:เช่น
jmathew

7

คุณสามารถใช้วิธีการทั่วไปต่อไปนี้เพื่อวัตถุประสงค์ของคุณ ควรแก้ไขปัญหาของคุณ

//Called method
-(NSMutableArray*)sortArrayList:(NSMutableArray*)arrDeviceList filterKeyName:(NSString*)sortKeyName ascending:(BOOL)isAscending{
    NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:sortKeyName ascending:isAscending];
    [arrDeviceList sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
    return arrDeviceList;
}

//Calling method
[self sortArrayList:arrSomeList filterKeyName:@"anything like date,name etc" ascending:YES];

6

หากคุณเพียงแค่เรียงลำดับอาร์เรย์NSNumbersคุณสามารถจัดเรียงพวกเขาด้วย 1 การโทร:

[arrayToSort sortUsingSelector: @selector(compare:)];

ใช้งานได้เพราะวัตถุในอาร์เรย์ ( NSNumberวัตถุ) ใช้วิธีการเปรียบเทียบ คุณสามารถทำสิ่งเดียวกันสำหรับNSStringวัตถุหรือแม้แต่อาร์เรย์ของวัตถุข้อมูลแบบกำหนดเองที่ใช้วิธีการเปรียบเทียบ

นี่คือตัวอย่างโค้ดโดยใช้บล็อกตัวเปรียบเทียบ มันเรียงลำดับของพจนานุกรมที่แต่ละพจนานุกรมมีตัวเลขในคีย์ "sort_key"

#define SORT_KEY @\"sort_key\"

[anArray sortUsingComparator: 
 ^(id obj1, id obj2) 
  {
  NSInteger value1 = [[obj1 objectForKey: SORT_KEY] intValue];
  NSInteger value2 = [[obj2 objectForKey: SORT_KEY] intValue];
  if (value1 > value2) 
{
  return (NSComparisonResult)NSOrderedDescending;
  }

  if (value1 < value2) 
{
  return (NSComparisonResult)NSOrderedAscending;
  }
    return (NSComparisonResult)NSOrderedSame;
 }];

โค้ดข้างต้นจะผ่านการทำงานของการรับค่าจำนวนเต็มสำหรับแต่ละคีย์การเรียงลำดับและการเปรียบเทียบพวกเขาเป็นภาพประกอบของวิธีการทำ เนื่องจากNSNumberวัตถุใช้วิธีการเปรียบเทียบจึงสามารถเขียนใหม่ได้ง่ายกว่า:

 #define SORT_KEY @\"sort_key\"

[anArray sortUsingComparator: 
^(id obj1, id obj2) 
 {
  NSNumber* key1 = [obj1 objectForKey: SORT_KEY];
  NSNumber* key2 = [obj2 objectForKey: SORT_KEY];
  return [key1 compare: key2];
 }];

หรือร่างกายของเครื่องมือเปรียบเทียบอาจถูกกลั่นลงไปที่ 1 บรรทัด:

  return [[obj1 objectForKey: SORT_KEY] compare: [obj2 objectForKey: SORT_KEY]];

ฉันมักจะชอบคำสั่งที่เรียบง่ายและตัวแปรชั่วคราวจำนวนมากเพราะรหัสอ่านง่ายขึ้นและง่ายต่อการดีบัก คอมไพเลอร์ปรับแต่งตัวแปรชั่วคราวให้เหมาะสมอยู่แล้วดังนั้นจึงไม่มีข้อได้เปรียบสำหรับเวอร์ชัน all-in-one-line


5

ฉันได้สร้างวิธีการหมวดหมู่ห้องสมุดขนาดเล็กที่เรียกว่าLinq ถึง ObjectiveCซึ่งทำให้การเรียงลำดับนี้ง่ายขึ้น การใช้วิธีการเรียงลำดับกับตัวเลือกคีย์คุณสามารถเรียงลำดับได้birthDateดังนี้:

NSArray* sortedByBirthDate = [input sort:^id(id person) {
    return [person birthDate];
}]

คุณควรเรียกมันว่า " LINQ to Objective-C "
Peter Mortensen

5

ฉันเพิ่งเรียงลำดับหลายระดับตามความต้องการที่กำหนดเอง

// จัดเรียงค่า

    [arrItem sortUsingComparator:^NSComparisonResult (id a, id b){

    ItemDetail * itemA = (ItemDetail*)a;
    ItemDetail* itemB =(ItemDetail*)b;

    //item price are same
    if (itemA.m_price.m_selling== itemB.m_price.m_selling) {

        NSComparisonResult result=  [itemA.m_itemName compare:itemB.m_itemName];

        //if item names are same, then monogramminginfo has to come before the non monograme item
        if (result==NSOrderedSame) {

            if (itemA.m_monogrammingInfo) {
                return NSOrderedAscending;
            }else{
                return NSOrderedDescending;
            }
        }
        return result;
    }

    //asscending order
    return itemA.m_price.m_selling > itemB.m_price.m_selling;
}];

https://sites.google.com/site/greateindiaclub/mobil-apps/ios/multilevelsortinginiosobjectivec


5

ฉันใช้sortUsingFunction ::ในบางโครงการของฉัน:

int SortPlays(id a, id b, void* context)
{
    Play* p1 = a;
    Play* p2 = b;
    if (p1.score<p2.score) 
        return NSOrderedDescending;
    else if (p1.score>p2.score) 
        return NSOrderedAscending;
    return NSOrderedSame;
}

...
[validPlays sortUsingFunction:SortPlays context:nil];

5

คุณใช้ NSSortDescriptor เพื่อเรียงลำดับ NSMutableArray ด้วยวัตถุที่กำหนดเอง

 NSSortDescriptor *sortingDescriptor;
 sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                       ascending:YES];
 NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];

4
-(NSMutableArray*) sortArray:(NSMutableArray *)toBeSorted 
{
  NSArray *sortedArray;
  sortedArray = [toBeSorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) 
  {
    return [a compare:b];
 }];
 return [sortedArray mutableCopy];
}

เหตุใดจึงต้องผ่านในอาร์เรย์ที่ไม่แน่นอนเมื่อส่งคืนอาร์เรย์ใหม่ ทำไมต้องสร้างเสื้อคลุม
vikingosegundo

3

การเรียงลำดับNSMutableArrayนั้นง่ายมาก:

NSMutableArray *arrayToFilter =
     [[NSMutableArray arrayWithObjects:@"Photoshop",
                                       @"Flex",
                                       @"AIR",
                                       @"Flash",
                                       @"Acrobat", nil] autorelease];

NSMutableArray *productsToRemove = [[NSMutableArray array] autorelease];

for (NSString *products in arrayToFilter) {
    if (fliterText &&
        [products rangeOfString:fliterText
                        options:NSLiteralSearch|NSCaseInsensitiveSearch].length == 0)

        [productsToRemove addObject:products];
}
[arrayToFilter removeObjectsInArray:productsToRemove];

2

จัดเรียงโดยใช้ NSComparator

หากเราต้องการเรียงลำดับวัตถุที่กำหนดเองที่เราต้องจัดเตรียมNSComparatorซึ่งใช้ในการเปรียบเทียบวัตถุที่กำหนดเอง บล็อกส่งคืนNSComparisonResultค่าเพื่อแสดงถึงลำดับของวัตถุทั้งสอง ดังนั้นในการเรียงลำดับอาเรย์ทั้งหมดNSComparatorจึงใช้วิธีดังต่อไปนี้

NSArray *sortedArray = [employeesArray sortedArrayUsingComparator:^NSComparisonResult(Employee *e1, Employee *e2){
    return [e1.firstname compare:e2.firstname];    
}];

การเรียงลำดับการใช้ NSSortDescriptor
สมมติว่าเป็นตัวอย่างว่าเรามีอาร์เรย์ที่มีอินสแตนซ์ของคลาสที่กำหนดเอง Employee มีแอตทริบิวต์ชื่อ, นามสกุลและอายุ ตัวอย่างต่อไปนี้แสดงให้เห็นถึงวิธีการสร้าง NSSortDescriptor ที่สามารถใช้เพื่อเรียงลำดับเนื้อหาอาร์เรย์ตามลำดับจากน้อยไปมากโดยคีย์อายุ

NSSortDescriptor *ageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES];
NSArray *sortDescriptors = @[ageDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];

จัดเรียงโดยใช้การเปรียบเทียบแบบกำหนดเอง
ชื่อเป็นสตริงและเมื่อคุณเรียงลำดับสตริงเพื่อแสดงต่อผู้ใช้คุณควรใช้การเปรียบเทียบที่แปลแล้วเสมอ บ่อยครั้งที่คุณต้องการทำการเปรียบเทียบแบบไม่สนใจตัวพิมพ์ ตัวอย่างต่อไปนี้มาพร้อมกับ (localizedStandardCompare :) เพื่อสั่งซื้ออาร์เรย์ด้วยชื่อและนามสกุล

NSSortDescriptor *lastNameDescriptor = [[NSSortDescriptor alloc]
              initWithKey:@"lastName" ascending:YES selector:@selector(localizedStandardCompare:)];
NSSortDescriptor * firstNameDescriptor = [[NSSortDescriptor alloc]
              initWithKey:@"firstName" ascending:YES selector:@selector(localizedStandardCompare:)];
NSArray *sortDescriptors = @[lastNameDescriptor, firstNameDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];

สำหรับการอ้างอิงและการสนทนาอย่างละเอียดโปรดดู: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/SortDescriptors/Articles/Creating.html
http://www.ios-blog.co.uk/tutorials / วัตถุประสงค์ -c / วิธีการจัดเรียง NSArray ที่มีวัตถุที่กำหนดเอง /


1

โพรโทคอลของ Swift และการเขียนโปรแกรมเชิงฟังก์ชันทำให้ง่ายมากที่คุณเพียงแค่ต้องทำให้คลาสของคุณสอดคล้องกับโพรโทคอล Comparable ใช้วิธีการที่จำเป็นโดยโพรโทคอลแล้วใช้ฟังก์ชันเรียงลำดับสูง (by:) เพื่อสร้างอาร์เรย์เรียงโดยไม่จำเป็นต้องใช้ อาร์เรย์ที่ไม่แน่นอนโดยวิธีการ

class Person: Comparable {
    var birthDate: NSDate?
    let name: String

    init(name: String) {
        self.name = name
    }

    static func ==(lhs: Person, rhs: Person) -> Bool {
        return lhs.birthDate === rhs.birthDate || lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedSame
    }

    static func <(lhs: Person, rhs: Person) -> Bool {
        return lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedAscending
    }

    static func >(lhs: Person, rhs: Person) -> Bool {
        return lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedDescending
    }

}

let p1 = Person(name: "Sasha")
p1.birthDate = NSDate() 

let p2 = Person(name: "James")
p2.birthDate = NSDate()//he is older by miliseconds

if p1 == p2 {
    print("they are the same") //they are not
}

let persons = [p1, p2]

//sort the array based on who is older
let sortedPersons = persons.sorted(by: {$0 > $1})

//print sasha which is p1
print(persons.first?.name)
//print James which is the "older"
print(sortedPersons.first?.name)

1

ในกรณีของฉันฉันใช้ "sortArrayUsingComparator" เพื่อเรียงลำดับอาร์เรย์ ดูรหัสด้านล่าง

contactArray = [[NSArray arrayWithArray:[contactSet allObjects]] sortedArrayUsingComparator:^NSComparisonResult(ContactListData *obj1, ContactListData *obj2) {
    NSString *obj1Str = [NSString stringWithFormat:@"%@ %@",obj1.contactName,obj1.contactSurname];
    NSString *obj2Str = [NSString stringWithFormat:@"%@ %@",obj2.contactName,obj2.contactSurname];
    return [obj1Str compare:obj2Str];
}];

นอกจากนี้วัตถุของฉันคือ

@interface ContactListData : JsonData
@property(nonatomic,strong) NSString * contactName;
@property(nonatomic,strong) NSString * contactSurname;
@property(nonatomic,strong) NSString * contactPhoneNumber;
@property(nonatomic) BOOL isSelected;
@end

1

คุณต้องสร้าง sortDescriptor แล้วคุณสามารถเรียงลำดับ nsmutablearray โดยใช้ sortDescriptor เหมือนด้านล่าง

 let sortDescriptor = NSSortDescriptor(key: "birthDate", ascending: true, selector: #selector(NSString.compare(_:)))
 let array = NSMutableArray(array: self.aryExist.sortedArray(using: [sortDescriptor]))
 print(array)

1

ใช้สิ่งนี้สำหรับวัตถุที่ซ้อนกัน

NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastRoute.to.lastname" ascending:YES selector:@selector(caseInsensitiveCompare:)];
NSMutableArray *sortedPackages = [[NSMutableArray alloc]initWithArray:[packages sortedArrayUsingDescriptors:@[sortDescriptor]]];

lastRoute เป็นวัตถุหนึ่งและวัตถุนั้นถือเป็นวัตถุที่วัตถุถือค่าสตริงนามสกุล


0

จัดเรียงแถวลำดับอย่างรวดเร็ว


สำหรับSwiftyคนด้านล่างเป็นเทคนิคที่สะอาดมากเพื่อให้บรรลุเป้าหมายข้างต้นสำหรับทั่วโลก ให้มีคลาสแบบกำหนดเองUserซึ่งมีคุณลักษณะบางอย่าง

class User: NSObject {
    var id: String?
    var name: String?
    var email: String?
    var createdDate: Date?
}

ตอนนี้เรามีอาร์เรย์ที่เราต้องจัดเรียงบนพื้นฐานของการcreatedDateขึ้นและ / หรือจากมากไปน้อย ดังนั้นให้เพิ่มฟังก์ชั่นสำหรับการเปรียบเทียบวันที่

class User: NSObject {
    var id: String?
    var name: String?
    var email: String?
    var createdDate: Date?
    func checkForOrder(_ otherUser: User, _ order: ComparisonResult) -> Bool {
        if let myCreatedDate = self.createdDate, let othersCreatedDate = otherUser.createdDate {
            //This line will compare both date with the order that has been passed.
            return myCreatedDate.compare(othersCreatedDate) == order
        }
        return false
    }
}

ตอนนี้ให้มีextensionการสำหรับArray Userในคำง่ายๆให้เพิ่มวิธีการเฉพาะสำหรับอาเรย์ของเหล่านั้นที่มีUserวัตถุอยู่ในนั้น

extension Array where Element: User {
    //This method only takes an order type. i.e ComparisonResult.orderedAscending
    func sortUserByDate(_ order: ComparisonResult) -> [User] {
        let sortedArray = self.sorted { (user1, user2) -> Bool in
            return user1.checkForOrder(user2, order)
        }
        return sortedArray
    }
}

การใช้งานสำหรับการสั่งซื้อน้อยไปมาก

let sortedArray = someArray.sortUserByDate(.orderedAscending)

การใช้งานสำหรับการสั่งซื้อมากไปน้อย

let sortedArray = someArray.sortUserByDate(.orderedAscending)

การใช้งานสำหรับการสั่งซื้อเดียวกัน

let sortedArray = someArray.sortUserByDate(.orderedSame)

วิธีการด้านบนextensionจะสามารถเข้าถึงได้หากArrayเป็นประเภท [User]| |Array<User>


0

เวอร์ชั่นของ Swift: 5.1

หากคุณมีโครงสร้างหรือคลาสที่กำหนดเองและต้องการเรียงลำดับโดยพลการคุณควรเรียก sort () โดยใช้การปิดท้ายที่เรียงลำดับตามฟิลด์ที่คุณระบุ นี่คือตัวอย่างการใช้อาร์เรย์ของโครงสร้างที่กำหนดเองที่เรียงลำดับตามคุณสมบัติเฉพาะ:

    struct User {
        var firstName: String
    }

    var users = [
        User(firstName: "Jemima"),
        User(firstName: "Peter"),
        User(firstName: "David"),
        User(firstName: "Kelly"),
        User(firstName: "Isabella")
    ]

    users.sort {
        $0.firstName < $1.firstName
    }

หากคุณต้องการส่งคืนอาร์เรย์ที่เรียงลำดับแทนที่จะเรียงลำดับให้ใช้ sort () ดังนี้:

    let sortedUsers = users.sorted {
        $0.firstName < $1.firstName
    }

0
  let sortedUsers = users.sorted {
    $0.firstName < $1.firstName
 }

คำถามเกี่ยวกับ NSMutableArray ไม่ใช่เกี่ยวกับการรวบรวม Arays ใน Swift
Ricardo

-2
NSMutableArray *stockHoldingCompanies = [NSMutableArray arrayWithObjects:fortune1stock,fortune2stock,fortune3stock,fortune4stock,fortune5stock,fortune6stock , nil];

NSSortDescriptor *sortOrder = [NSSortDescriptor sortDescriptorWithKey:@"companyName" ascending:NO];

[stockHoldingCompanies sortUsingDescriptors:[NSArray arrayWithObject:sortOrder]];

NSEnumerator *enumerator = [stockHoldingCompanies objectEnumerator];

ForeignStockHolding *stockHoldingCompany;

NSLog(@"Fortune 6 companies sorted by Company Name");

    while (stockHoldingCompany = [enumerator nextObject]) {
        NSLog(@"===============================");
        NSLog(@"CompanyName:%@",stockHoldingCompany.companyName);
        NSLog(@"Purchase Share Price:%.2f",stockHoldingCompany.purchaseSharePrice);
        NSLog(@"Current Share Price: %.2f",stockHoldingCompany.currentSharePrice);
        NSLog(@"Number of Shares: %i",stockHoldingCompany.numberOfShares);
        NSLog(@"Cost in Dollars: %.2f",[stockHoldingCompany costInDollars]);
        NSLog(@"Value in Dollars : %.2f",[stockHoldingCompany valueInDollars]);
    }
    NSLog(@"===============================");
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.