ios - كيف يمكنني فرز NSMutableArray مع كائنات مخصصة في ذلك؟




objective-c sorting cocoa-touch (21)

رتب باستخدام NSComparator

إذا أردنا تصنيف الكائنات المخصصة ، نحتاج إلى توفير NSComparator ، والذي يُستخدم لمقارنة الكائنات المخصصة. إرجاع الكتلة قيمة NSComparisonResult للدلالة على ترتيب الكائنات اثنين. لذلك من أجل فرز مجموعة كاملة يتم استخدام NSComparator النحو التالي.

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

الفرز باستخدام NSSortDescriptor
لنفترض ، على سبيل المثال ، أن لدينا صفيفًا يحتوي على أمثلة لفئة مخصصة ، فالموظف لديه سمات الاسم الأول واسم العائلة والعمر. يوضح المثال التالي كيفية إنشاء 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/objective-c/how-to-sort-nsarray-with-custom-objects/

ما أريد فعله يبدو بسيطًا جدًا ، ولكن لا يمكنني العثور على أي إجابات على الويب. لدي NSMutableArray من الكائنات ، ودعونا نقول أنها كائنات "شخص". أريد فرز NSMutableArray بواسطة Person.birthDate وهو NSDate.

أعتقد أن لها علاقة بهذه الطريقة:

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

في Java ، أجعل الكائن تنفيذًا قابل للمقارنة ، أو استخدم Collections.sort مع مقارنة مخصصة مضمنة ... كيف تقوم بذلك على الأرض في Objective-C؟


ستوفر لك مجموعات iOS 4 :)

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 قليلاً من الوصف


بدءًا من iOS 4 ، يمكنك أيضًا استخدام كتل للفرز.

لهذا المثال بالذات أفترض أن الكائنات الموجودة في الصفيف لديك لها طريقة "position" ، والتي تقوم بإرجاع 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];

ملحوظة: سيتم تجهيز المصفوفة "المصنفة" تلقائيًا.


لقد جربت كل شيء ، لكن هذا عمل بالنسبة لي. في الفصل الدراسي لديّ فصل آخر اسمه " crimeScene " ، وأريد الفرز حسب خاصية " crimeScene ".

هذا يعمل مثل السحر:

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

إن بروتوكولات Swift والبرمجة الوظيفية تجعل من السهل عليك فقط جعل صفك مطابقاً للبروتوكول المقارن ، وتنفيذ الطرق التي يتطلبها البروتوكول ثم استخدام الدالة المرتبة عالية الجودة (بواسطة:) لإنشاء مصفوفة مرتبة بدون الحاجة إلى استخدام صفائف قابلة للتغيير من جانب الطريق.

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)

هناك خطوة مفقودة في إجابة جورج شولي الثانية ، لكنها تعمل بشكل جيد في ذلك الوقت.

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

مقارنة الطريقة

إما أن تقوم بتطبيق طريقة مقارنة لكائنك:

- (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: والأساليب المستندة إلى كتلة أسرع قليلاً بشكل عام ، من استخدام NSSortDescriptor لأن الأخير يعتمد على KVC. تتمثل الميزة الأساسية لطريقة NSSortDescriptor أنها توفر طريقة لتحديد ترتيب الفرز باستخدام البيانات ، بدلاً من التعليمة البرمجية ، مما يجعل من السهل إعداد العناصر بحيث يمكن للمستخدمين فرز NSTableView بالنقر فوق صف الرأس.


لقد استخدمت 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];

أنا فعلت فرز على مستوى متعدد على أساس متطلبات مخصصة.

// فرز القيم

    [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


في حالتي ، أستخدم "sortedArrayUsing COMparator" لتصنيف مصفوفة. انظر إلى الرمز أدناه.

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

إذا كنت تقوم فقط بفرز مصفوفة من NSNumbers ، فيمكنك فرزها باستخدام مكالمة واحدة:

[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];
 }];

أو حتى يمكن تقريب جسم المقارنة إلى سطر واحد:

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

أميل إلى تفضيل عبارات بسيطة والكثير من المتغيرات المؤقتة لأن التعليمة البرمجية أسهل في القراءة ، وأسهل في التصحيح. يقوم المترجم بتحسين المتغيرات المؤقتة على أي حال ، لذلك لا توجد ميزة للإصدار المتكامل في سطر واحد.


يجب عليك إنشاء 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)

ترتيب المصفوفة في سويفت

ل Swifty Person أدناه هو تقنية نظيفة للغاية لتحقيق هدف أعلاه على الصعيد العالمي. يتيح الحصول على فئة مخصصة من User والتي لها بعض السمات.

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

الآن لدينا مجموعة نحتاج إلى createdDate على أساس 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)

لا يمكن الوصول إلى الطريقة المذكورة أعلاه إلا إذا كان Array من النوع [User] || Array<User>


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

شكرا ، انها تعمل بشكل جيد ...


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(@"===============================");

يمكنك استخدام الطريقة العامة التالية لغرضك. يجب أن تحل مشكلتك.

//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];

أنا فعلت هذا في iOS 4 باستخدام كتلة. كان عليه أن يلقي عناصر صفيفي من معرف إلى نوع الفصل. في هذه الحالة ، كانت فئة تسمى درجة مع خاصية تسمى النقاط.

كما تحتاج إلى تحديد ما يجب فعله إذا لم تكن عناصر الصفيف الخاص بك هي النوع الصحيح ، لهذا المثال عدت للتو 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;

ملاحظة: هذا هو فرز بترتيب تنازلي.


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

فرز 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];

يمكنك فرز مجموعة من الكائنات المخصصة باستخدام الفرز السريع. يرجى الاطلاع على المثال أدناه باستخدام Swift 4

func sortArrayOfPersonInAscendingOrder() {
        if self.arrSortingPersons != nil, self.arrSortingPersons.count > 0 {
            self.arrSortingPersons.sort(by: { (person1, person2) -> Bool in
                return person1.birthDate < person2.birthDate
            })
        }

        print("Sorted Array In Ascending Order:\n\(self.arrSortingPersons)")
    }

اعتبارًا من Xcode 7 ، يمكنك تشغيل " Fast, Whole Module Optimization . هذا من شأنه أن يزيد من أدائك على الفور.







ios objective-c sorting cocoa-touch nsmutablearray