GeneCode
GeneCode

Reputation: 7588

Sort dictionary by multiple keys

I have myDict in the format of:

{
  data1 = { 
             key1 = abc
             key2 = abc
             key3 = abc
             key4 = abc
          },
  data2 = { 
             key1 = abc
             key2 = abc
             key3 = abc
             key4 = abc
          }
  ..
}

I use the following code to sort myDict and get the the sorted data by keys.

    sortedArr = [myDict keysSortedByValueUsingComparator:
                 ^NSComparisonResult(NSDictionary* obj1, NSDictionary* obj2)
                 {
                     NSComparisonResult result = NSOrderedSame;
                     if(obj1[@"key1"] != nil && obj2[@"key1"]!=nil)
                     {
                         return [obj2[@"key1"] compare:obj1[@"key1"]];
                     }
                     else
                         return result;
                 }];

sortedArr:

(data1,data2,data3,...)

question is how do i sort myDict using 2 keys instead of one because I face an issue if key1 value are the same, then i want it to be sorted by key2.

Upvotes: 0

Views: 147

Answers (2)

Blazej SLEBODA
Blazej SLEBODA

Reputation: 9935

You cannot insert nil into collections (dictionaries, arrays, index sets, etc).

You can, however, insert [NSNull null] into them as this is what they made it for

Below you can find the code which sorts the first level dictionaries by all keys within subDictinaries.

NSMutableDictionary *md = [NSMutableDictionary dictionary];

NSMutableDictionary *data1 = [NSMutableDictionary dictionary];

[data1 setObject:@"abc" forKey:@"key1"];
[data1 setObject:@"abc" forKey:@"key2"];
[data1 setObject:@"abc" forKey:@"key3"];
[data1 setObject:@"a" forKey:@"key4"];

NSMutableDictionary *data2 = [NSMutableDictionary dictionary];

[data2 setObject:@"abc" forKey:@"key1"];
[data2 setObject:@"abc" forKey:@"key2"];
[data2 setObject:@"abc" forKey:@"key3"];
[data2 setObject:@"b" forKey:@"key4"];

NSMutableDictionary *data3 = [NSMutableDictionary dictionary];

[data3 setObject:@"abc" forKey:@"key1"];
[data3 setObject:@"abc" forKey:@"key2"];
[data3 setObject:@"abc" forKey:@"key3"];
[data3 setObject:@"c" forKey:@"key4"];

[md setObject:data1 forKey:@"data1"];
[md setObject:data2 forKey:@"data2"];
[md setObject:data3 forKey:@"data3"];

NSArray *allKeys = @[@"key1", @"key2", @"key3", @"key4"];

NSArray *sortedData = [md keysSortedByValueUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {

    for (NSString *key in allKeys) {

        if (obj1[key] != nil && obj2[key] != nil) { // Checking if both keys exist

            NSComparisonResult result = [obj2[key] compare:obj1[key]];

            if (result != NSOrderedSame) {

                return result;

            }

        } else { // One of keys is missing

            return NSOrderedSame;

        }

    }

    return NSOrderedSame; // No keys

}];

NSLog(@"%@", sortedData);

Output:

( data3, data2, data1 )

Upvotes: 0

James Webster
James Webster

Reputation: 32066

You just need to account for the case for each key where the comparison returns NSOrderedSame. You can iterate the keys like this:

NSArray *allKeys = @[@"key1", @"key2", @"key3", ...];
for (NSString *aKey in allKeys)
{
    if(obj1[aKey] != nil && obj2[aKey] != nil)
    {
        NSComparisonResult result = [obj2[aKey] compare:obj1[aKey]]; 
        if (result != NSOrderedSame) return result;
    }
}
return NSOrderedSame;

This answer is substantially different from my original answer, all credit to Larme for this solution

Upvotes: 3

Related Questions