20

I have an NSMutableDictionary that maps NSString to NSString (although the values are NSStrings, they are really just integers).

For example consider the following mappings,

"dog" --> "4"
"cat" --> "3"
"turtle" --> "6"

I'd like to end up with the top 10 entries in the dictionary sorted by decreasing order of the value. Can someone show me code for this? Perhaps there is an array of keys and another array of values. However it is, I don't mind. I'm just trying to have it be efficient.

Thank you!

Juan Boero
  • 6,281
  • 1
  • 44
  • 62
CodeGuy
  • 28,427
  • 76
  • 200
  • 317

6 Answers6

47

Get the Array of the Values, sort that array and then get the key corresponding to the value.

You can get the values with:

NSArray* values = [myDict allValues];
NSArray* sortedValues = [values sortedArrayUsingSelector:@selector(comparator)];

But, if the collection is as you show in your example, (I mean, you can infer the value from the key), you can always sort the keys instead messing with the values.

Using:

NSArray* sortedKeys = [myDict keysSortedByValueUsingSelector:@selector(comparator)];

The comparator is a message selector which is sent to the object you want to order.

If you want to order strings, then you should use a NSString comparator. The NSString comparators are i.e.: caseInsensitiveCompare or localizedCaseInsensitiveCompare:.

If none of these are valid for you, you can call your own comparator function

[values sortedArrayUsingFunction:comparatorFunction context:nil]

Being comparatorFunction (from AppleDocumentation)

NSInteger intSort(id num1, id num2, void *context)
{
    int v1 = [num1 intValue];
    int v2 = [num2 intValue];
    if (v1 < v2)
        return NSOrderedAscending;
    else if (v1 > v2)
        return NSOrderedDescending;
    else
        return NSOrderedSame;
}
Ingve
  • 1,086
  • 2
  • 20
  • 39
HyLian
  • 4,999
  • 5
  • 33
  • 40
  • Okay, so let's say I want to use your second method. What exactly is "comparator." I'm sorry I've never used this method before. Does that mean I need to write my own function? What would it look like? Thanks!! – CodeGuy Dec 29 '10 at 23:31
  • 2
    @HyLian What if NSDictionary contains duplicate values for different keys. How you will track which key should be pick up? – Samir Jwarchan Jul 10 '13 at 04:02
  • _[Sorting a Dictionary](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Collections/Articles/Dictionaries.html#//apple_ref/doc/uid/20000134-SW4)_ in Apple's **[Collections Programming Guide](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Collections/Collections.html#//apple_ref/doc/uid/10000034-BBCFIHFH)** had more information on this topic. – John Chacho May 24 '16 at 16:09
4

Use this method:

- (NSArray *)sortKeysByIntValue:(NSDictionary *)dictionary {

  NSArray *sortedKeys = [dictionary keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2) {
      int v1 = [obj1 intValue];
      int v2 = [obj2 intValue];
      if (v1 < v2)
          return NSOrderedAscending;
      else if (v1 > v2)
          return NSOrderedDescending;
      else
          return NSOrderedSame;
  }];
  return sortedKeys;
}

Call it and then create a new dictionary with keys sorted by value:

NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
                           @"4", @"dog",
                           @"3", @"cat",
                           @"6", @"turtle", 
                           nil];

NSArray *sortedKeys = [self sortKeysByIntValue:dictionary];
NSMutableDictionary *sortedDictionary = [[NSMutableDictionary alloc] init];

for (NSString *key in sortedKeys){
    [sortedDictionary setObject:dictionary[key] forKey:key];
}
kraftydevil
  • 5,144
  • 6
  • 43
  • 65
4

The simplest way is:

NSArray *sortedValues = [[yourDictionary allValues] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
NSMutableDictionary *orderedDictionary=[[NSMutableDictionary alloc]init];
for(NSString *valor in sortedValues){
    for(NSString *clave in [yourDictionary allKeys]){
        if ([valor isEqualToString:[yourDictionary valueForKey:clave]]) {
            [orderedDictionary setValue:valor forKey:clave];
        }
    }
}
Tejeshwar
  • 7
  • 1
  • 4
Luis Andrés García
  • 5,852
  • 10
  • 43
  • 57
3

Sorting the keys and using that to populate an array with the values:

NSArray *keys = [dict allKeys];
NSArray *sKeys = [keys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
NSMutableArray *sValues = [[[NSMutableArray alloc] init] autorelease];

for(id k in sKeys) {
    id val = [dict objectForKey:k];
    [sValues addObject:val];
}
X Slash
  • 4,133
  • 4
  • 27
  • 35
hburde
  • 1,441
  • 11
  • 6
0

if you want to sort data in ascending order for key 'name' for such kind of Example then this may help you.

arrayAnimalList = [ { 'name' = Dog, 'animal_id' = 001 }, { 'name' = Rat, 'animal_id' = 002 }, { 'name' = Cat, 'animal_id' = 003 } ];

This is a code which help you to get sorted array

//here you have to pass key for which you want to sort data

 NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];

   NSArray *sortDescriptors = [NSArray arrayWithObject:descriptor];

  // here you will get sorted array in 'sortedArray'
  NSMutableArray * sortedArray = [[arrayAnimalList sortedArrayUsingDescriptors:sortDescriptors] mutableCopy];
0
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"interest"  ascending:YES];
[unsortedArray sortUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];
recentSortedArray = [stories copy];
Dilip Lilaramani
  • 1,126
  • 13
  • 28