views:

208

answers:

4

I know you can use any object as key for NSDictionary but the problem is will it be able to retrieve the correct value? Support I have an entry where the key = {1,3,5} and value = { @"hello" }. Will I be able to retrieve from this dictionary entry by passing in the set {3,5,1}?

In order words, is the key matched based on the pointer or does it actually compare the contents of the set? (And if it is the former, how can I overcome this?)

A: 

Yes.

Try this in irb:

require 'osx/cocoa'
abc=OSX::NSSet.setWithArray([1,2,3])
cba=OSX::NSSet.setWithArray([3,2,1])
dict=OSX::NSMutableDictionary.dictionary
dict[abc] = 'hello'
puts dict[cba]

(it works, because isEqual: for NSSet is true when you'd expect it to be and NSDictionary bases its actions on that)

Timo Metsälä
+6  A: 

The equality of keys is done using isEqual on the keys in question. Thus, the comparison of {1,3,5} and {3,5,1} (assuming that the numbers are represented by NSNUmber instances) will be YES.

lyonanderson
That, and `NSSet` conforms to `NSCopying`, which is the other requirement for `NSDictionary` keys.
Dave DeLong
+1: Only other caveat is that the keys of a dictionary must be strings if you want to access/mutate them using key-value coding.
Jarret Hardie
+1  A: 

Yep it seems to work nicely (not sure if there are any gotchas).

NSMutableDictionary * dict = [NSMutableDictionary dictionary];

NSSet * set;
set = [NSSet setWithObjects:@"a", @"b", @"c", @"d", nil];
[dict setObject:@"1" forKey:set];

set = [NSSet setWithObjects:@"b", @"c", @"d", @"e", nil];
[dict setObject:@"2" forKey:set];

id key;
NSEnumerator * enumerator = [dict keyEnumerator];
while ((key = [enumerator nextObject]))
    NSLog(@"%@ : %@", key, [dict objectForKey:key]);

set = [NSSet setWithObjects:@"c", @"b", @"e", @"d", nil];
NSString * value = [dict objectForKey:set];
NSLog(@"set: %@ : key: %@", set, value);

Outputs:

2009-12-08 15:42:17.885 x[4989] (d, e, b, c) : 2
2009-12-08 15:42:17.887 x[4989] (d, a, b, c) : 1
2009-12-08 15:42:17.887 x[4989] set: (d, e, b, c) : key: 2
stefanB
One simple gotcha; the keys must me immutable, therefor `copy` is called on the keys. So any `NSMutableSet` will be copied into a new `NSSet` when used as key.
PeyloW
The keys are immutable, that's why I'm using NSSet.
stefanB
+1  A: 

Yes (since a set conforms to NSCopying and implements isEqual:), with one catch: Do not use a mutable set, or any other mutable object, as a key. You will mutate it, whereupon you will break your ability to look up its value in the dictionary.

Peter Hosey