4

Overview

  • I am using fast enumeration to iterate through an NSDictionary instance
  • I expected the NSDictionary instance to be enumerated based on the ascending order of the key but that doesn't seem to be the case

What I want to do:

  • I want to be able iterate through the NSDictionary instance in the ascending order of the key using fast enumeration

Note: Pls see expected output vs actual output

Questions

  1. Am i making a mistake with my implementation ?
  2. Does NSDictionary's fast enumeration guarantee ordering based on keys ?
  3. If not then is there a work around for this and yet use fast enumeration ?

Example

#import<Foundation/Foundation.h>

int main()
{
    system("clear");

    NSDictionary *d1 = nil;

    @autoreleasepool
    {   

        d1 = [[NSDictionary alloc] initWithObjectsAndKeys: @"AAA", [NSNumber numberWithInt:10], 
              @"BBB", [NSNumber numberWithInt:20],               
              @"CCC", [NSNumber numberWithInt:30],               
              nil];
    }   

    for(NSNumber* n1 in d1)     //I expected fast enumeration for NSDictionary to be based on the 
        //ascending order of the key but that doesn't seem to be the case
    {
        printf("key = %p"
               "\t [key intValue] = %i"
               "\t value = %s\n", 
               n1, 
               [n1 intValue], 
               [[d1 objectForKey:n1] UTF8String]);
    }   

    return(0);
}

Expected Output

key = 0xa83      [key intValue] = 10     value = AAA
key = 0x1483     [key intValue] = 20     value = BBB
key = 0x1e83     [key intValue] = 30     value = CCC

Actual Output

key = 0x1e83     [key intValue] = 30     value = CCC
key = 0xa83      [key intValue] = 10     value = AAA
key = 0x1483     [key intValue] = 20     value = BBB
WrightsCS
  • 50,551
  • 22
  • 134
  • 186
user1046037
  • 16,755
  • 12
  • 92
  • 138
  • possible duplicate of [NSDictionary with ordered keys](http://stackoverflow.com/questions/376090/nsdictionary-with-ordered-keys) – bryanmac Dec 16 '11 at 04:22

3 Answers3

13
for (NSString *key in [[d1 allKeys] sortedArrayUsingSelector:@selector(compare:)])
{
    id value = [d1 valueForKey:key];
    ...
}
WrightsCS
  • 50,551
  • 22
  • 134
  • 186
NSResponder
  • 16,861
  • 7
  • 32
  • 46
  • But although that uses fast enumeration on the resulting sorted array of keys, it does not use fast enumeration on the dictionary, which is what the OP said he wanted to do... – matt Dec 16 '11 at 04:34
  • Thanks for the response NSResponder and Matt, that is a nice work around. – user1046037 Dec 16 '11 at 05:04
2
  1. No your implementation is correct.
  2. NSDictionary fast enumeration does not guarantee sorting (and it will not output anything in order because of implementation as hashed container).
  3. No, you have to sort it yourself.
Daniel
  • 30,896
  • 18
  • 85
  • 139
1

There is no guaranties about the order in which you will receive your object.

allKeys
Returns a new array containing the dictionary’s keys.
- (NSArray *)allKeys
Return Value
A new array containing the dictionary’s keys, or an empty array if the dictionary has no entries.
Discussion
The order of the elements in the array is not defined.

So my suggestion is, if your dictionary doesn't change often, cache an NSArray with the key in the order you want them.
If your dictionary often change, you may have to sort allKeys when you need them.

Vincent Bernier
  • 8,674
  • 4
  • 35
  • 40
  • Thanks Vince, that is a nice suggestion. I suppose if the order of the key is more important than the order of the value, then I could probably create the dictionary with the key as my value and my value as my key. Then use the method keysSortedByValueUsingSelector: – user1046037 Dec 16 '11 at 05:00
  • @user1046037 it always depend on what your goal is and what you need. Arrays are good at keeping thing in order, so depending on the circumstance you might event consider some custom class held in an array and ordered based on one of it's property. I'm just throwing ideas... – Vincent Bernier Dec 16 '11 at 05:16