Getting NSDictionary keys sorted by their respective values

37,015

Solution 1

The NSDictionary Method keysSortedByValueUsingComparator: should do the trick.

You just need a method returning an NSComparisonResult that compares the object's values.

Your Dictionary is

NSMutableDictionary * myDict;

And your Array is

NSArray *myArray;

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

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

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

          return (NSComparisonResult)NSOrderedAscending;
     }

     return (NSComparisonResult)NSOrderedSame;
}];

Just use NSNumber objects instead of numeric constants.

BTW, this is taken from: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Collections/Articles/Dictionaries.html

Solution 2

Here's a solution:

NSDictionary *dictionary; // initialize dictionary
NSArray *sorted = [[dictionary allKeys] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [[dictionary objectForKey:obj1] compare:[dictionary objectForKey:obj2]];
}];

Solution 3

The simplest solution:

[dictionary keysSortedByValueUsingSelector:@selector(compare:)]

Solution 4

Here i have done something like this:

NSMutableArray * weekDays = [[NSMutableArray alloc] initWithObjects:@"Sunday",@"Monday",@"Tuesday",@"Wednesday",@"Thursday",@"Friday",@"Saturday", nil];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSMutableArray *dictArray = [[NSMutableArray alloc] init];

for(int i = 0; i < [weekDays count]; i++)
{
    dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:i],@"WeekDay",[weekDays objectAtIndex:i],@"Name",nil];
    [dictArray addObject:dict];
}
NSLog(@"Before Sorting : %@",dictArray);

@try
{
    //for using NSSortDescriptor
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"WeekDay" ascending:YES];
    NSArray *descriptor = @[sortDescriptor];
    NSArray *sortedArray = [dictArray sortedArrayUsingDescriptors:descriptor];
    NSLog(@"After Sorting : %@",sortedArray);

    //for using predicate
    //here i want to sort the value against weekday but only for WeekDay<=5
   int count=5;
    NSPredicate *Predicate = [NSPredicate predicateWithFormat:@"WeekDay <=%d",count];
    NSArray *results = [dictArray filteredArrayUsingPredicate:Predicate];

    NSLog(@"After Sorting using predicate : %@",results);
}
@catch (NSException *exception)
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Sorting cant be done because of some error" message:[NSString stringWithFormat:@"%@",exception] delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
    [alert setTag:500];
    [alert show];
    [alert release];
}
Share:
37,015
Eric
Author by

Eric

Updated on July 09, 2022

Comments

  • Eric
    Eric almost 2 years

    I have an NSMutableDictionary with integer values, and I'd like to get an array of the keys, sorted ascending by their respective values. For example, with this dictionary:

    mutableDict = {
        "A" = 2,
        "B" = 4,
        "C" = 3,
        "D" = 1,
    }
    

    I'd like to end up with the array ["D", "A", "C", "B"]. My real dictionary is much larger than just four items, of course.

  • Hermann Klecker
    Hermann Klecker about 12 years
    Richard's proposal is more elegant than mine because NSNumber already comes with a suitable compare function but mine is probably more general.
  • Richard J. Ross III
    Richard J. Ross III about 12 years
    In most cases, this solution will work fine, but what my answer has is the ability to support other types that respond to the -compare:
  • ViruMax
    ViruMax about 10 years
    working correctly for strings starting with alphabates only, but when there is a string starting with number 10, its comming between first string starting with "A" and third string starting with "A"
  • nemesis
    nemesis over 9 years
    Check the answer above, it's more intuitive and concise, even though this does the same thing.
  • Pradumna Patil
    Pradumna Patil almost 9 years
    how to write that compare function
  • onCompletion
    onCompletion over 8 years
    Please explain the compare method also.
  • Mr.G
    Mr.G over 7 years
    This will returns the key list , is there anyway that can get the dictionary directly , instead of having list of sorted keys in array
  • Hermann Klecker
    Hermann Klecker over 7 years
    @Mr.G, no there is no way as NSDictionary and NSMutableDictionare are not sorted. You cannot sort them and expect them to be sorted afterwards.
  • dgatwood
    dgatwood over 7 years
    For existing types (e.g. NSString), that method already exists. For anything you create yourself, the method should return NSOrderedAscending, NSOrderedSame, or NSOrderedDescending, depending on the order. See the documentation for compare:options:range: for more info.