views:

2081

answers:

3

Being new to Cocoa, and probably not knowing all of the potential classes available that already have this functionality neatly wrapped in an OO class, here's an algorithm inquiry. What's the best bet to count how many times a particular key occurs in an array of multiple NSDictionary instances?

Essentially my data structure (in this case an NSArray) might contain several NSDictionary instances at any given time, each one having the same keys, potentially different values. Some values repeat. I'd like to be able to know how many times a particular key/value appears. Example:

{ foo => 1, bar => 2 } { foo => 1, bar => 3 } { foo => 2, bar => 1 }

In this case I'm interested that foo=>1 occured 2 times and foo=>2 occured 1 time. Is building an instance of NSCountedSet the best way to go about this? Perhaps a C linked-list?

Thanks.

+4  A: 

You may want to rethink how you are structuring your data. I'd track something like this while adding to the NSArray instead of trying to discover it at a later time. You might create a new class to handle adding and removing the data so that you can keep your own counts of the data.

Brian C. Lane
+1  A: 
NSDictionary * dict1 = [[NSDictionary alloc] initWithObjectsAndKeys:
                        [NSNumber numberWithInt:1], @"foo",
                        [NSNumber numberWithInt:2], @"bar", nil];
NSDictionary * dict2 = [[NSDictionary alloc] initWithObjectsAndKeys:
                        [NSNumber numberWithInt:1], @"foo",
                        [NSNumber numberWithInt:3], @"bar", nil];
NSDictionary * dict3 = [[NSDictionary alloc] initWithObjectsAndKeys:
                        [NSNumber numberWithInt:2], @"foo",
                        [NSNumber numberWithInt:1], @"bar", nil];
NSArray * arrayOfDictionaries = [[NSArray alloc] initWithObjects:
                                 dict1, dict2, dict3, nil];

// count all keys in an array of dictionaries (arrayOfDictionaries):

NSMutableDictionary * countKeys = [[NSMutableDictionary alloc] initWithCapacity:0];
NSCountedSet * counts = [[NSCountedSet alloc] initWithCapacity:0];

NSArray * keys;
NSString * pairString;
NSString * countKey;
for (NSDictionary * dictionary in arrayOfDictionaries)
{
    keys = [dictionary allKeys];
    for (NSString * key in keys)
    {
        pairString = [NSString stringWithFormat:@"%@->%@", key, [dictionary valueForKey:key]];
        if ([countKeys valueForKey:pairString] == nil)
        {
            [countKeys setValue:[NSString stringWithString:pairString] forKey:pairString];
        }
        countKey = [countKeys valueForKey:pairString];
        { [counts addObject:countKey]; }
    }
}

NSLog(@"%@", counts);

[counts release];
[countKeys release];

[arrayOfDictionaries release];
[dict1 release];
[dict2 release];
[dict3 release];
e.James
Phew! That was more difficult than I thought it would be. As Brian C. Lane said, you may want to rethink how this is implemented.
e.James
Thanks James. I wasn't aware that NSCountedSet existed. Wish it was mentioned in Hillegass's book. :-) Cheers!
eJames: You're doing work yourself that you don't need to. See my answer: http://stackoverflow.com/questions/307695/algorithm-keeping-count-of-keyvalue-pair-in-nsdictionary#307898
Peter Hosey
A: 
NSCountedSet *keyCounts = [NSCountedSet set];
for (NSDictionary *dict in myDictionaries)
 [keyCounts unionSet:[NSSet setWithArray:[dict allKeys]]];
Peter Hosey
I had this wrong the first time, too. He actually wants the count of unique pairs, not just the count of keys. If one of the dictionaries has a value of 2 for key "foo", and another one has a value of 3 for the same key, that should count as two unique entries in the set.
e.James
Yeah, I know. I was more responding to your entry than the original question. The original question is much harder to do with primitive collections; he would, I think, be better served by making model objects.
Peter Hosey
You're probably right about the model objects. Thanks for the heads-up about my code. I didn't originally consider NSCountedSet, but I can see that your snippet would be useful. The downvote on this answer wasn't mine, but it gets an upvote from me now.
e.James