Create NSDictionary with order support - objective-c

I need a NSDictionary object that not only support key->value storage but also support key sequence just like Array does.
Is there something exists on Objective-C ?

Monolo's answer is the right way to do this.
[self allKeys] does not return ordered sequence. it's an NSSet style.
And I write a Class named PLHash that has many features:
key value storage
key order support
items max size control ( set a maxItems to PLHash and it will keep items by FIFO )
here is the URL
https://github.com/xhan/PlutoLand/blob/master/PlutoLand/Additions/PLHash.h

I have found this article (and the linked source code) useful: http://cocoawithlove.com/2008/12/ordereddictionary-subclassing-cocoa.html

Nothing built in, but you can use an array of keys along side the dictionary to record the order.

You would be best off either getting the allkeys array and sorting that then getting the value for a key or making your own class to store objects the way you want them. It really sounds like you are doing something NSDictionary really wasn't built to do, what are you trying to do that you want the keys sorted?

One option is to create a category on nsdictionary, call it sortedKeys or something, which returns a sorted [self allKeys].
Update: Now that I'm not responding from my phone, here's my suggestion, written verbosely for clarity, and assuming you're using ARC:
#interface NSDictionary (sort)
- (NSArray *)sortedKeys;
#end
#implementation NSDictionary (sort)
- (NSArray *)sortedKeys {
NSArray *keyArray = [self allKeys];
NSArray *sortedKeyArray = [keyarray sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
return sortedKeyArray;
}
#end
I personally don't think that subclassing NSDictionary is the way to go.

Related

Getting set of objects from NSSet using the HASH

this is actually a question that i'd been trying to solve...
i need to implement this functionality in NSSet...
I know how hash tables and sets works.. and NSSet seems to store the pointer to the objects inside the hash table using the HASH as the index of that array... when more than one object falls in that hash.. it uses isEqual to detect which one of the objects is the member we search... that means...
HASH value => gives the index of the array of pointers in the hash table, and each one of those pointers points to an array (or some collection) that holds the objects with that hash (as it iterates over it to detect which object is the member)... this is a fairly common data struct...
My question is... is there a way to retrieve the array of objects that is being pointed by the hash table... i need ALL the objects that have the SAME HASH VALUE inside an NSSet...
i need this in order to quickly process proximity between points...
Is there a way? i know i can use a predicate using
[NSPredicate predicateWithFormat:#"hash == %u",hash];
but this uses an enumeration and is not as fast as it needs to be (real fast)
Is there a way or should i create a HASH TABLE from scratch? (or use core foundation)
Thanks and sorry for the trouble!
if you want the object in an array just call -allObjects, if you want all hashes, then you will have to iterate through them, because they are longs and can't be stored in an NSArray directly.
I had the idea to make a mock object that overrides its own hash, then you could search through an array for the index of this object that is pretending to be your object.
#interface MockHasher : NSObject{
NSUInteger mockHash;
}
#property(assign,nonatomic,getter = hash,setter = setHash:)NSUInteger mockHash;
#end
#implementation MockHasher
#synthesize mockHash;
-(BOOL)isEqual:(id)object{return YES;}
-(BOOL)isEqualTo:(id)object{return YES;}
#end
example:
NSSet * myset = [NSSet setWithObject:#(1)];
MockHasher * mockObject = [[MockHasher new] autorelease];
mockObject.hash = #(1).hash;
NSArray * allObjects = [myset allObjects];
NSUInteger i = [allObjects indexOfObject:mockObject];
id result = [allObjects objectAtIndex:i];
NSLog(#"result = %#",result);
It is fragile, because it is depending on the array asking the object passed in for isEqual: rather than asking the iterated object... I don't know how reliable this is... but it worked in my test.
As of iOS 6.0 and MacOS 10.5, you now have an actual NSHashTable object to work with. Its modeled after NSSet, but instead is it's own thing. Here's some additional Apple documentation on Hash Tables, as well.

Appending NSDictionary to other NSDictionary

I have one NSDictionary and it loads up UITableView. If a user scrolls more and more, I call API and pull new data. This data is again in the form of an NSDictionary. Is it possible to add the new NSDictionary to the existing one?
You looking for this guy:
[NSMutableDictionary addEntriesFromDictionary:]
Make sure your UITableView dictionary is an NSMutableDictionary!
Check it here
Use NSMutableDictionary addEntriesFromDictionary to add the two dictionaries to a new mutable dictionary. You can then create an NSDictionary from the mutable one, but it's not usually necessary to have a dictionary non-mutable.
Is your NSDictionary full of other NSDictionaries? It sounds like you would need an NSMutableArray that you could add NSDictionaries to at the end. Assuming you can control the flow of data coming in and wouldn't run the risk of duplicates in your array, you could certainly append the data.
NSMutableArray *array = [[NSMutableArray alloc] init];
arrayCount = [array count]; // check the item count
[array addObject:dictToAppend];
Without seeing how you are implementing it, I can't provide more detailed code examples. Appending items is easy to do, but know it can only be done with mutable versions of Arrays or Dictionaries. Hope this helps a little.

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.

Quick NSMutableArray Question

I was wondering, would using a NSMutableArray be the best way for making an array that i will be adding objects to? Or, just a regular NSArray? secondly, I'm trying to make something sort of like an ArrayList in java (so there is no limit to the size), and I would like to know how to do that. What I've thought of is to make a bigger array and copy older array into it. My code:
- (void) addAccount:(BankAccount *)b
{
accountCount = [NSNumber numberWithDouble:[accountCount doubleValue] + 1];
NSMutableArray *oldList = accounts;
accounts = [[NSMutableArray alloc] (some code to make bigger and copy over)];
}
P.S. I taught myself this language yesterday, so I may not understand you response if it's too advanced
NSMutableArrays are what you want. Also, NSMutableArrays are already like ArrayLists or STL vectors, or anything else with "no limit to the size". You can say [myArray addObject:someObject]; until you run out of memory, and it will just keep resizing itself as needed.
The difference between an NSMutableArray and an NSArray lies in the meaning of the word "mutable". i.e.: A mutable array can be modified after it's created whereas a "normal" NSArray is immutable and can't be modified after it's created.
As such, using an NSMutableArray and adding objects to it via the addObject: method would seem an ideal solution.
If you want to be adding objects all at once use NSArray. If you're going to be adding some objects now, then more later, use NSMutableArray.
Your code snippet doesn't make much sense. To make an NSMutableArray, do this:
NSMutableArray *array = [NSMutableArray array];
If you don’t need an order (normally you don’t), use a NSSet/NSMutableSet.

Detect changes in NSArray in ObjC

I need to detect change in NSArray object - that is if some object was added/removed to/from NSArray or was just edited in-place. Are there some integrated NSArray hash functions for this task - or I need to write my own hashing function for NSArray ? Maybe someone has different solution ? Any ideas ?
All objects have a -hash method but not all objects have a good implementation.
NSArray's documentation doesn't define it's result, but testing reveals it returns the length of the array - not very useful:
NSLog(#"%lu", #[#"foo"].hash); // output: 1
NSLog(#"%lu", #[#"foo", #"bar"].hash); // output: 2
NSLog(#"%lu", #[#"hello", #"world"].hash); // output: 2
If performance isn't critical, and if the array contains <NSCoding> objects then you can simply serialise the array to NSData which has a good -hash implementation:
[NSArchiver archivedDataWithRootObject:#[#"foo"]].hash // 194519622
[NSArchiver archivedDataWithRootObject:#[#"foo", #"bar"]].hash // 123459814
[NSArchiver archivedDataWithRootObject:#[#"hello", #"world"]].hash // 215474591
For better performance there should be an answer somewhere explaining how to write your own -hash method. Basically call -hash on every object in the array (assuming the array contains objects that can be hashed reliably) and combine each together mixed in with some simple randomising math.
You could use an NSArrayController, which is Key-Value-Observing compliant. Unfortunately NSArray is only KVC compliant. This way you can easily monitor the array controller's arrangedObjects property. This should solve your problem.
Also, see this question: Key-Value-Observing a to-many relationship in Cocoa