santobedi
santobedi

Reputation: 858

Unexpected result with sortedArrayUsingComparator in Objective-C

I am trying to sort the keys of an NSMutableDictionary with their respective values (values in ascending order). My code snippet is as follows:

NSArray *sortedKeysWithValues = [[myDict allKeys] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [[myDict objectForKey:obj2] compare:[myDict objectForKey:obj1]];}];

The contents of the NSMutableDictionary are:

{
 806: "-89.06";
 802: "-75.12";
 837: "-77.76";
 803: "-84.75";
 808: "-115";
 804: "-102.12";
 813: "-115";
 805: "-115";
 801: "-67.53";
 836: "-70.36";
}

After the execution of the above code, the contents on sortedKeyWithValues becomes:

(
806,
803,
837,
802,
836,
801,
808,
813,
805,
804,
) 

Notice that the key with the highest value lies at 5th index of sortedKeyWithValues. And the key for 2nd highest value is on the 4th index and so on. It continues until the first index. The key with the value next to the first index lies at the last index of sortedKeyWithValues it goes up to the 6th index.

The order of the objects at sortedKeyWithValues that I'm expecting is:

(
801,
836,
802,
837,
803,
806,
804,
805,
813,
808,
)

What could be the cause for this strange outcome while using sortedArrayUsingComparator? Is it due to a bug with the method or some silly mistake from my side?

Thank you!

Upvotes: 0

Views: 248

Answers (4)

vadian
vadian

Reputation: 285190

It's not a bug. You are comparing strings not numbers.

NS(Mutable)Dictionary has a dedicated method keysSortedByValueUsingSelector to sort keys by values and the selector localizedStandardCompare sorts strings numerically. The comparator API is not needed.

NSArray *sortedKeysWithValues = [myDict keysSortedByValueUsingSelector:@selector(localizedStandardCompare:)];

Alternatively use a comparator with option NSNumericSearch

id numericSort = ^(NSString * key1, NSString * key2) {
    return [key1 compare:key2 options: NSNumericSearch];
};

NSArray *sortedKeysWithValues = [dictionary keysSortedByValueUsingComparator:numericSort];

Upvotes: 1

Faysal Ahmed
Faysal Ahmed

Reputation: 7669

Try doing this:

NSArray *myArray;

myArray = [myDict keysSortedByValueUsingComparator: ^(id obj1, id obj2) {

     if ([obj1 doubleValue] > [obj2 doubleValue]) {

          return (NSComparisonResult)NSOrderedDescending;
     }
     if ([obj1 doubleValue] < [obj2 doubleValue]) {

          return (NSComparisonResult)NSOrderedAscending;
     }

     return (NSComparisonResult)NSOrderedSame;
}];

Upvotes: 1

Aris
Aris

Reputation: 1559

That is happening because the values of the NSDictionary are NSStrings. compare: is doing an alphabetical sort.

Quick and dirty fix based on your code:

NSArray *sortedKeysWithValues = [[dic allKeys] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){
    return [@([dic[obj2] doubleValue]) compare:@([dic[obj1] doubleValue])];}];

Upvotes: 1

ingconti
ingconti

Reputation: 11656

only a couple of notes:

1) what is myDict inside comparison call back?

2) in callback you usually have to get values inside obj1 / obj2 AND compare data members inside them: (eventually casting them... ) for example:

NSArray *sortedPeople = [self.persons sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){

Person *p1 = (Person *)obj1;
Person *p2 = (Person *)obj2;
    return [p1.surname compare:p2.surname];

}];

so I need to know why you use MyDict.

Upvotes: 1

Related Questions