2

I have an Input Array of Dictionaries :

myArray = (
    {
        name:"abc";
        time:"6:00";
    },
    {
        name:"xyz";
        time:"7:00";
    },
    .
    .
)

I want Output Dictionary like this :

myDictionary = {
    "6:00":(
        {
            name:"abc";
            time:"6:00";
        },
        .
        .
     )
     "7:00":(
        {
            name:"xyz";
            time:"7:00";
        },
        .
        .
     )
}

What I tried :

I succeeded to get an array of distinct times using this line :

NSArray *arrTempKeys = [myArray valueForKeyPath:@"@distinctUnionOfObjects.Time"];

and then used the predicate inside for loop for arrTempKeys, to get all the dictionaries with same time value :

NSPredicate *pred = [NSPredicate predicateWithFormat:@"Date == %@",str];
NSArray *arrTemp = [myArray filteredArrayUsingPredicate:pred];

Finally, I assigned this arrTemp as an Object for the Key time and got the desired result.


What I want :

I know there are many other ways to get this output. But I just want to know if there is any single KVC coding line or any other optimum way available to do this thing.

Bhavin
  • 27,155
  • 11
  • 55
  • 94
  • 1
    Similar questions here: http://stackoverflow.com/questions/22288481/group-nsdictionary-by-dates and here: http://stackoverflow.com/questions/20925537/grouping-nsarray-of-nsdictionary-based-on-a-key-in-nsdictionay. There is also some discussion about the "optimal" method. – Martin R Mar 10 '14 at 13:37
  • @MartinR: Oops.. !! Actually I tried to google before asking the question. But it's always hard to find the similar question when you don't know "what will be the title of similar questions". Still if you find that this question is not going to add any value to our community then mark it as duplicate. – Bhavin Mar 11 '14 at 05:39

3 Answers3

4

You want too much. Just write a simple loop. It will be the most efficient, clearest, and probably the most reliable solution:

NSMutableDictionary* myDict = [NSMutableDictionary dictionary];
for (NSDictionary* innerDict in myArray) {
    NSString* time = innerDict[@"time"];
    NSMutableArray* innerArray = myDict[time];
    if (innerArray == nil) {
        innerArray = [NSMutableArray array];
        [myDict setValue:innerArray forKey:time];
    }
    [innerArray addObject:innerDict];
}
Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
Hot Licks
  • 47,103
  • 17
  • 93
  • 151
3

NSDictionary can do this with an assist from NSArray and KVC.

Try this:

NSDictionary *myDictionary = [NSMutableDictionary dictionaryWithObjects:myArray
                                                                forKeys:[myArray valueForKey:@"time"];

That should work, since NSArray's version of -valueForKey: returns an array of the values returned by each of it's elements for the key.

Caution: While the code above is concise and seems to solve your problem, it's not without some pitfalls. The main one is that a dictionary can only have one value for a given key, which means that if two or more of the entries in the array have the same value for the key @"time", only one of them (probably the last) will be represented in the resulting dictionary. Also, if any entry is missing a value for @"time", that entry will have [NSNull null] as its key. As above, if there are two or more missing the time value, only one will be represented in the dictionary.

Edit: Looking more closely at your question, I see that the times in the items are not necessarily distinct, so Hot Licks' answer will probably make more sense for you.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • Smart, but: The result of this is a dictionary of string->dictionary, not string->array, as requested. – Nikolai Ruhe Mar 10 '14 at 15:50
  • @NikolaiRuhe I'm not sure what you mean about strings, but perhaps it's just a language difference. I think your point is that my solution doesn't work well for non-distinct keys -- you get a dictionary with one dictionary per key rather than a dictionary with an array of dictionaries for each key. I agree completely. – Caleb Mar 10 '14 at 15:58
0

No, there isn't. KVC allows you to navigate key paths, but it doesn't do collation of data in this way based on the content of key paths.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • Thanks for the Answer. I just want to know if there is any better approach available other than the one I used or if there is any optimization required in my approach. :) – Bhavin Mar 10 '14 at 13:31
  • Don't optimise till you have a reason to. Your code is code-efficient, not necessarily runtime-efficient (you do a lot of looping). Any change to this will likely need more code. – Wain Mar 10 '14 at 13:38