1

Say I have a dictionary with keys (words) and values (scores) as follows:

GOD    8
DONG   16
DOG    8
XI     21

I would like to create an NSArray of dictionary keys (words) that is sorted first by score then alphabetically. From the example above this would be:

XI
DONG
DOG
GOD

What's the best way to achieve this?

djskinner
  • 8,035
  • 4
  • 49
  • 72

3 Answers3

1

I would use and NSArray of NSDictionaries and then implement it using NSSortDescriptors:

NSSortDescriptor *sdScore = [NSSortDescriptor alloc] initWithKey:@"SCORE" ascending:NO];
NSSortDescriptor *sdName = [NSSortDescriptor alloc] initWithKey:@"NAME" ascending:YES];
NSArray *sortedArrayOfDic = [unsortedArrayOfDic sortedArrayUsingDescriptors:[NSArray arrayWithObjects: sdScore, sdName, nil]];
CSolanaM
  • 3,138
  • 1
  • 20
  • 21
  • How do I construct this array of dictionaries from my original dictionary? – djskinner Sep 24 '12 at 19:00
  • Ok, figured it out. I expected it to be much simpler. This would be a one-liner in C# LINQ! – djskinner Sep 24 '12 at 19:18
  • @DanielSkinner If it's one-liners you want, perhaps you could write a category based on Carlos' solution to do what you want to do. – Extra Savoir-Faire Sep 24 '12 at 20:17
  • but what will happen if numeric value is 2 as well as 21 ?? then in sorted array, dictionary having number 21 will be followed by dictionary having number 2 – Mrug Jan 30 '14 at 13:26
0

Carlos' answer is the correct one I'm just posting the full code I ended up with just in case anyone is interested:

NSDictionary *dataSourceDict = [NSDictionary dictionaryWithObjectsAndKeys:
                      [NSNumber numberWithInt:8], @"GOD",
                      [NSNumber numberWithInt:16], @"DONG",
                      [NSNumber numberWithInt:8], @"DOG",
                      [NSNumber numberWithInt:21], @"XI", nil];

NSSortDescriptor *scoreSort = [NSSortDescriptor sortDescriptorWithKey:@"SCORE" ascending:NO];
NSSortDescriptor *wordSort = [NSSortDescriptor sortDescriptorWithKey:@"WORD" ascending:YES];
NSArray *sorts = [NSArray arrayWithObjects:scoreSort, wordSort, nil];


NSMutableArray *unsortedArrayOfDict = [NSMutableArray array];

for (NSString *word in dataSourceDict)
{
    NSString *score = [dataSourceDict objectForKey:word];
    [unsortedArrayOfDict addObject: [NSDictionary dictionaryWithObjectsAndKeys:word, @"WORD", score, @"SCORE",  nil]];
}
NSArray *sortedArrayOfDict = [unsortedArrayOfDict sortedArrayUsingDescriptors:sorts];

NSDictionary *sortedDict = [sortedArrayOfDict valueForKeyPath:@"WORD"];

NSLog(@"%@", sortedDict);

Related: NSDictionary split into two arrays (objects and keys) and then sorted both by the objects array (or a similar solution)

Community
  • 1
  • 1
djskinner
  • 8,035
  • 4
  • 49
  • 72
0

I couldn't test this because i'm not on a Mac (sorry if I misspelled something), but:

NSDictionary *dic1 = [NSDictionary dictionaryWithObjectsAndKeys:@"GOD", @"WORD", [NSNumber numberWithInt:8], @"SCORE", nil];
NSDictionary *dic2 = [NSDictionary dictionaryWithObjectsAndKeys:@"DONG", @"WORD", [NSNumber numberWithInt:16], @"SCORE", nil];
NSDictionary *dic3 = [NSDictionary dictionaryWithObjectsAndKeys:@"DOG", @"WORD", [NSNumber numberWithInt:8], @"SCORE", nil];
NSDictionary *dic4 = [NSDictionary dictionaryWithObjectsAndKeys:@"XI", @"WORD", [NSNumber numberWithInt:21], @"SCORE", nil];

NSSortDescriptor *scoreSort = [NSSortDescriptor sortDescriptorWithKey:@"SCORE" ascending:NO];
NSSortDescriptor *wordSort = [NSSortDescriptor sortDescriptorWithKey:@"WORD" ascending:YES];

NSArray *sortedArrayOfDic = [[NSArray arrayWithObjects:dic1, dic2, dic3, dic4, nil] sortedArrayUsingDescriptors:[NSArray arrayWithObjects:scoreSort, wordSort, nil]];

NSLog(@"%@", [sortedArrayOfDict valueForKeyPath:@"WORD"]);

This would do the same but a bit reduced and avoiding an iteration.

CSolanaM
  • 3,138
  • 1
  • 20
  • 21
  • Ok but if I was just given an NSDictionary of unknown size and contents I'd had to iterate like I did, right? Or can I still simplify things? – djskinner Sep 25 '12 at 11:06
  • I think you'll have to iterate. But let me say that if you place all data in an NSDictionary with pairs of key (words) and value (scores) you lose the essence of the dictionary data structure. This is thought to be used with pairs of field identifier and value of the field. The identifier must be unchanged along the dictionary so you can access it directly with objectForKey. Think it as something like a HashMap in Java (if you know Java). What you're getting using in that way is only two simple arrays, one of keys and other of values, only linked between them by the index at the dictionary. – CSolanaM Sep 25 '12 at 19:06