object arranging in NSMutableDictionary - objective-c

here is my dictionary and its values
NSMutableDictionary *myDic=[NSMutableDictionary Dictionary];
[myDIC setObject:#""];
[myDIC setObject:string1 forKey:key1];
[myDIC setObject:string2 forKey:key2];
[myDIC setObject:string3 forKey:key3];
so up to here i have filled up my dictionary.now i want to read them through a for loop.
for (NSString *key in myDic ){
}
here is my problem! inside this loop the my first key will be key1 but i seems it start from the last key that i have set before!
is there anyone who can tell me why ? and how i can meet my expectation as what i explained?

NSDictionary is not an index base collection it's a Hashtable, and like all HashTable, the elements are store according to some logic base on some Hash that you don't know. If you look in the documentation for NSDictionary you will find a sentence that state that there is not guaranty about the order into which the item will be retrieve.
If you want your key to be retrieve in a specific order you will need to keep your keys in an NSArray, in the order that you want them.
Or you can sort your keys when you need them.
NSArray * allKeys = [myDict allKeys];
allKeys = [allKeys sortedArrayUsing// [see the documentation for all options][1] ];

I came across this problem before. The order of a specific element in NSArray of NSMutableArray is decided by its index.
But unlike NSArray or NSMutableArray,The elements order in NSMutableDictionary or NSDictionary is undefined and nobody knows because its mechanism.
I chose a paragraph from Mac OS X Developer Libary for you:
"Internally, a dictionary uses a hash table to organize its storage
and to provide rapid access to a value given the corresponding key.
However, the methods defined for dictionaries insulate you from the
complexities of working with hash tables, hashing functions, or the
hashed value of keys. The methods take keys directly, not in their
hashed form."

Related

Unable to sort NSMutableDictionary [Objective C]

I populate an NSMutableDictionary with some Json, the problem is that even if the Json is ordered correctly the NSMutableDictionary reorder the values randomly (at least I don't know what's the logic behind it).
I tried to reorder the NSMutableDictionary using the following method but I still get the same result as the Json:
NSArray* sortedKeys = [theData allKeys];
NSMutableArray* orderHelper = [[NSMutableArray alloc] initWithArray:sortedKeys];
[orderHelper sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
return [str1 compare:str2 options:(NSNumericSearch)];
}];
NSMutableDictionary *sortedDictionary = [[NSMutableDictionary alloc] init];
for (NSString *key in orderHelper){
[sortedDictionary setObject:theData[key] forKey:key];
}
where theData is the first NSMutableDictionary containing the Json.
debugging I can see that the NSMutableArray gets ordered correctly but then on the for the NSMutableArray randomly reorders the items.
Does anyone have a solution for this?
Dictionaries (or Maps) are generally not an ordered data structure, and this is also the case for NSDictionary and the like. That means that the iteration order of your dictionary or the order of the allKeys array does not correspond to the insertion order of the associations you put into the dictionary.
So since the order is important to you, you have two options:
1) Use an OrderedDictionary implementation which does exactly that (preserve insertion order). There is none in the Objective-C standard library, but open-source alternatives are available.
2) Keep track of the order yourself in a separate NSArray in which you put the keys of your dictionary. Then, instead of iterating over your dictionary directly, you iterate over this array and read the corresponding values from the dictionary.
The internal order of a dictionary is entirely implementation-specific and of no value to you, since it might even be subject to changes. But very easily put, you can think about it the following way: The dictionary will assign a numerical value to each of your keys (e.g. foo is mapped to 0 and bar to 1. When you insert this key, it will add the value to a bucket at the corresponding numerical index. So regardless of the insertion order, foo will always end up in the first bucket, and bar will always end up in the second bucket. This is the order you can observe when subsequently iterating the dictionary.

NSMutableDictionary Sorted Keys and Objects did not Creating

I have an array for users, I want create a contact list.
I'm sorting objects and keys alphabetically.
NSArray *sortedKeys = [[contactListDictionary allKeys] sortedArrayUsingSelector: #selector(caseInsensitiveCompare:)];
NSArray *objects = [contactListDictionary objectsForKeys:sortedKeys notFoundMarker:[NSNull null]];
After this, I can initialize dictionary again with sorted keys and
objects.
contactListDictionary = [NSMutableDictionary dictionaryWithObjects:objects forKeys:sortedKeys];
But it did not sorting keys and objects. They are mixing in NSMutableDictionary, what can I do for this situation ?
You can't do anything about this, that is, not in the way you are now trying to.
The NSDictionary class does not allow you to tell it in what order to store its keys; that's just not the way it is implemented.
But you already found out that you can get the keys, in the desired order, in an array. There should be no need for the dictionary itself to be ordered, its purpose is to give you a fast lookup mechanimsm, and it does. If you want, for example, to display the keys in order, simply create a (temporary) array created the way you already now how to.

How can I do a multidimensional lookup table in Objective-C?

New to Objective-C here...
I have a unique string code as the key that I'd like to use to look up associated values.
It seems an NSDictionary is what I'm looking for but I believe this is only used to lookup one value for a given key.
Can anyone provide the code on how to declare/fill a multidimensional immutable NSDictionary? Also the code to retrieve the values?
Also, please let me know I'm going about this the wrong way
Thanks
EDIT: example of array within a dictionary .... using example data from your comment.
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
NSArray *firstSet = [[NSArray alloc] initWithObjects:43, 22];
NSArray *secondSet = [[NSArray alloc] initWithObjects:32, 50];
[myDictionary setValue:firstSet forKey:#"010"];
[myDictionary setValue:secondSet forKey:#"011"];
// Get a value out - should be the 50 that you want
NSInteger *myValue = [[myDictionary objectForKey:#"011"] objectAtIndex:1];
Not tested - but should be 95% right. Does this make sense?
You can make any object you want be the value for a given key in an NSDictionary. This includes NSArray or even another NSDictionary. Using either of these would allow you to associate multiple values with one key.
For nested NSDictionaries or custom KVC-complient classes you can use keyPaths, and for nested NSArrays indexPaths.
Also stackoverflow will give you many examples.

Searching NSArray for an object

I have NSArray consisting of NSDictionary objects. Need to find index in NSArray of object with matching key name in NSDictionary. Dictionary has only 1 element. What is the fastest way of doing that? Filter with predicate and then use indexOfObject?
That method would certainly work, but if you're looking for speed, you need to change your structure. Arrays aren't meant to be searched this way. However, it's what NSDictionary was built for. If you have a unique key you're searching for, why not store your dictionaries in an NSDictionary and use the much, much faster objectForKey: method?
If you also need to maintain an ordering, you could create a custom "ordered dictionary" class using an NSMutableArray of the keys in your dictionary.

Can I change an NSDictionary's key?

I have an NSDictionary object that is populated by instances of NSMutableString for its keys and objects. I have been able to change the key by changing the original NSMutableString with the setString: method. They key however remains the same regardless of the contents of the string used to set the key initially.
My question is, is the key protected from being changed meaning it will always be the same unless I remove it and add another to the dictionary?
Thanks.
The keys are -copy'd when the items are set, so you can't changing it afterwards is useless.
Methods that add entries to dictionaries—whether as part of initialization (for all dictionaries) or during modification (for mutable dictionaries)—copy each key argument (keys must conform to the NSCopying protocol) and add the copies to the dictionary. Each corresponding value object receives a retain message to ensure that it won’t be deallocated before the dictionary is through with it.
You could use CFDictionary with kCFTypeDictionaryKeyCallBacks, or just replace the item:
id value = [dictionary objectWithKey:oldKey];
[dictionary setObject:value withKey:newKey];
[dictionary removeObjectForKey:oldKey];
Try using NSMutableDictionary, instead.
You can create a copy of the dictionary, filtering the keys as you go. I do this for converting between camel-case and underscores when populating objects from JSON using KVC. See my refactoring library, es_ios_utils, for source. ESNSCategories.h provides:
#interface NSMutableDictionary(ESUtils)
//Changes keys using keyFilter. If keyFilter generates duplicate non-unique keys, objects will be overwritten.
-(void)addEntriesFromDictionary:(NSDictionary*)d withKeyFilter:(NSString*(^)(NSString*))keyFilter;
...
So to make all keys upper case, you could do something like:
NSMutableDictionary *md = [NSMutableDictionary dictionaryWithCapacity:oldDictionary.count];
[md addEntriesFromDictionary:oldDictionary
withKeyFilter:^NSString*(NSString *key) {
return key.uppercaseString;
}];