-3

I am passing NSDictionary to my function as a parameter. I want it's key and values to be in order as I inserted. for eg. expected output is:

 mutable dict:{
            zKey1 = Value1;
            fKey2 = Value2;
            aKey3 = Value3;
        } 

I have tried following ways to create and set value for keys.

    NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc]init];
        [mutableDict setObject:@"Value1" forKey:@"zKey1"];
        [mutableDict setObject:@"Value2" forKey:@"fKey2"];
        [mutableDict setObject:@"Value3" forKey:@"aKey3"];

    NSMutableDictionary *dic2=[[NSMutableDictionary alloc]initWithObjectsAndKeys:@"1004",@"userId",@"cucumber",@"domain",@"168d5c02f ",@"token",@"1004",@"userId1",@"cucumber",@"domain1",@"168d5c02f ",@"token1", nil];


    NSDictionary * dict = [NSDictionary
                               dictionaryWithObjects:@[@"Ravi",@"33",@"India",@"India"]
                               forKeys:@[@"name",@"age",@"location",@"country"]];
        NSArray *sortedKeys = [[dict allKeys] sortedArrayUsingSelector: @selector(compare:)];

        NSMutableArray *sortedValues = [NSMutableArray array];
        for (NSString *key in sortedKeys) {
            [sortedValues addObject: [dict objectForKey: key]];
        }

    NSString *obj1=@"1004";
        NSString *obj2=@"cucumber";
        NSString *obj3=@"168d5c02f";

        NSString *key1=@" userId";
        NSString *key2=@"domain";
        NSString *key3=@"token";
        NSLog(@"dict %@",dict);

        NSDictionary *dict8 =[NSDictionary
                              dictionaryWithObjects:@[obj1,obj2,obj3]
                              forKeys:@[key1,key2,key3]];

But nothing has worked I am always getting output as

    mutable dict:{
        aKey3 = Value3;
        fKey2 = Value2;
        zKey1 = Value1;
    } 


    dict8 {
        domain = cucumber;
        token = 168d5c02f;
        userId = 1004;
    }

     dict {
        age = 33;
        country = India;
        location = India;
        name = Ravi;
    }

    dic= {
        domain = cucumber;
        domain1 = cucumber;
        token = "168d5c02f ";
        token1 = "168d5c02f ";
        userId = 1004;
        userId1 = 1004;
    }

It is always sorting values according to alphabetical order of keys. Many people say that NSDictionary is an unsorted container. But it does gets sorted. Need help desperately. Thank you in advance.

  • 2
    `NSDictionary` is not ordered by default. It will always be without any order. To create an ordered, dictionary, you will need to override the existing form of the Data structure. You can read [This tutorial](http://www.cocoawithlove.com/2008/12/ordereddictionary-subclassing-cocoa.html) to achieve your end. – NSNoob Mar 11 '16 at 07:22
  • Nope, it's not a "sorted by key" NSDictionary even if you added them in order. If the output is in sequence, it's just you getting lucky. You can print them out by enumerate the keys with desired order via a sorted key NSArray, but not directly with the NSDictionary itself. – Cai Mar 11 '16 at 07:25
  • why not use NSMutableArray ? syntax is simple too .. `@[@{"key1":value1},@{"key2":value2},@{"key3":value3}] ` – aahsanali Mar 11 '16 at 07:26
  • But I am not getting output in sequence. It is always sorted alphabetically according to the keys. As I shown. – Prasad Bulbule Mar 11 '16 at 07:28

1 Answers1

4

NSDictionary is not ordered by default. It will always be without any order. To create an ordered dictionary, you will need to override the existing form of the Data structure. You can read This tutorial to achieve your end.

To summarize the tutorial (Because everyone hates link-only answers and links can die any time):

NSDictionary stores its keys in a hash table, which is unordered by design. Since this lack of order is fundamental to the hash table storeage, you have to perform subclassing of NSMutableDictionary (and hence reimplementation of the storage).

In your .h file

//
//  OrderedDictionary.h
//  OrderedDictionary
//
//  Created by Matt Gallagher on 19/12/08.
//  Copyright 2008 Matt Gallagher. All rights reserved.
//
//  Permission is given to use this source code file without charge in any
//  project, commercial or otherwise, entirely at your risk, with the condition
//  that any redistribution (in part or whole) of source code must retain
//  this copyright and permission notice. Attribution in compiled projects is
//  appreciated but not required.
//

#import <Cocoa/Cocoa.h>

@interface OrderedDictionary : NSMutableDictionary
{
    NSMutableDictionary *dictionary;
    NSMutableArray *array;
}

- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex;
- (id)keyAtIndex:(NSUInteger)anIndex;
- (NSEnumerator *)reverseKeyEnumerator;

@end

In your .m file:

//
//  OrderedDictionary.m
//  OrderedDictionary
//
//  Created by Matt Gallagher on 19/12/08.
//  Copyright 2008 Matt Gallagher. All rights reserved.
//
//  Permission is given to use this source code file without charge in any
//  project, commercial or otherwise, entirely at your risk, with the condition
//  that any redistribution (in part or whole) of source code must retain
//  this copyright and permission notice. Attribution in compiled projects is
//  appreciated but not required.
//

#import "OrderedDictionary.h"

NSString *DescriptionForObject(NSObject *object, id locale, NSUInteger indent)
{
    NSString *objectString;
    if ([object isKindOfClass:[NSString class]])
    {
        objectString = (NSString *)[[object retain] autorelease];
    }
    else if ([object respondsToSelector:@selector(descriptionWithLocale:indent:)])
    {
        objectString = [(NSDictionary *)object descriptionWithLocale:locale indent:indent];
    }
    else if ([object respondsToSelector:@selector(descriptionWithLocale:)])
    {
        objectString = [(NSSet *)object descriptionWithLocale:locale];
    }
    else
    {
        objectString = [object description];
    }
    return objectString;
}

@implementation OrderedDictionary

- (id)init
{
    return [self initWithCapacity:0];
}

- (id)initWithCapacity:(NSUInteger)capacity
{
    self = [super init];
    if (self != nil)
    {
        dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity];
        array = [[NSMutableArray alloc] initWithCapacity:capacity];
    }
    return self;
}

- (void)dealloc
{
    //This method is pre-ARC. Manual Release commands don't work now. 
    //[dictionary release]; 
    //[array release];
    //[super dealloc];
}

- (id)copy
{
    return [self mutableCopy];
}

- (void)setObject:(id)anObject forKey:(id)aKey
{
    if (![dictionary objectForKey:aKey])
    {
        [array addObject:aKey];
    }
    [dictionary setObject:anObject forKey:aKey];
}

- (void)removeObjectForKey:(id)aKey
{
    [dictionary removeObjectForKey:aKey];
    [array removeObject:aKey];
}

- (NSUInteger)count
{
    return [dictionary count];
}

- (id)objectForKey:(id)aKey
{
    return [dictionary objectForKey:aKey];
}

- (NSEnumerator *)keyEnumerator
{
    return [array objectEnumerator];
}

- (NSEnumerator *)reverseKeyEnumerator
{
    return [array reverseObjectEnumerator];
}

- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex
{
    if (![dictionary objectForKey:aKey])
    {
        [self removeObjectForKey:aKey];
    }
    [array insertObject:aKey atIndex:anIndex];
    [dictionary setObject:anObject forKey:aKey];
}

- (id)keyAtIndex:(NSUInteger)anIndex
{
    return [array objectAtIndex:anIndex];
}

- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
{
    NSMutableString *indentString = [NSMutableString string];
    NSUInteger i, count = level;
    for (i = 0; i < count; i++)
    {
        [indentString appendFormat:@"    "];
    }

    NSMutableString *description = [NSMutableString string];
    [description appendFormat:@"%@{\n", indentString];
    for (NSObject *key in self)
    {
        [description appendFormat:@"%@    %@ = %@;\n",
            indentString,
            DescriptionForObject(key, locale, level),
            DescriptionForObject([self objectForKey:key], locale, level)];
    }
    [description appendFormat:@"%@}\n", indentString];
    return description;
}

@end

You can Download Matt Gallagher's orderedDictionary here.

Community
  • 1
  • 1
NSNoob
  • 5,548
  • 6
  • 41
  • 54