I'm trying to find a good solution to split an array of dictionaries in a smaller dictionaries keyed by a common value between them.
Here is an example i JSON, I start from this:
{
"field": [
{
"id": 6,
"name": "Andrea"
},
{
"id": 67,
"name": "Francesco"
},
{
"id": 8,
"name": "Maria"
},
{
"id": 6,
"name": "Paolo"
},
{
"id": 67,
"name": "Sara"
}
]
}
I'd like to get a result like:
{
"field": [
{
"6": [
{
"name": "Andrea",
"id": 6
},
{
"name": "Paolo",
"id": 6
}
],
"67": [
{
"name": "Sara",
"id": 67
},
{
"name": "Francesco",
"id": 67
}
],
"8": [
{
"name": "Maria",
"id": 8
}
]
}
]
}
I managed using this code, it works, but I'm wondering if exist something more correct and fast:
NSArray * array = ...;
NSSortDescriptor *sorter1=[[NSSortDescriptor alloc]initWithKey:@"id" ascending:YES selector:@selector(compare:)];
NSSortDescriptor *sorter2=[[NSSortDescriptor alloc]initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];
NSArray *sortDescriptors=[NSArray arrayWithObjects:sorter1,sorter2,nil];
array = [array sortedArrayUsingDescriptors:sortDescriptors];
//////////////////////////////SPLITTER
NSMutableArray * subcategorySplittedArray = [[NSMutableArray alloc]initWithCapacity:30];
NSNumber * lastID=[[array objectAtIndex:0]objectForKey:@"id"];
NSMutableArray * shopArray = [[NSMutableArray alloc]initWithCapacity:100];
NSMutableDictionary * catDict = nil;
for (NSDictionary * dict in array) {
NSNumber * catID = [dict objectForKey:@"id"];
if ([lastID isEqualToNumber:catID]) {
[shopArray addObject:dict];
}
else {
catDict = [[NSMutableDictionary alloc]init ];
[catDict setObject:[shopArray copy] forKey:lastID];
[subcategorySplittedArray addObject:catDict];
[shopArray removeAllObjects];
[shopArray addObject:dict];
lastID = catID;
}
}
catDict = [[NSMutableDictionary alloc]init ];
[catDict setObject:[shopArray copy] forKey:lastID];
[subcategorySplittedArray addObject:catDict];
////////////////////////////////////
return subcategorySplittedArray;
}
NSMutableDictionary* result = [NSMutableDictionary dictionary];
NSArray* ids = [array valueWithKey:@"id"];
NSSet* uniqueIDs = [NSSet setWithArray:ids];
for (NSNumber* anID in uniqueIDs)
{
NSPredicate* pred = [NSPredicate predicateWithFormat:@"id == %@", anID];
NSArray* dictsForID = [array filteredArrayUsingPredicate:pred];
[result setObject:dictsForID forKey:anID];
}
If there are lots of IDs, you may be able to speed this up a bit by building a predicate with a variable reference outside of the loop and then just substituting the variable in to produce the id-specific predicate for each pass through the loop.
By the way, in your question, the result "field" is still an array for some reason. I don't think it needs to be.
Updated to make just one pass:
NSMutableDictionary* result = [NSMutableDictionary dictionary];
for (NSDictionary* dict in array)
{
NSNumber* anID = [dict objectForKey:@"id"];
NSMutableArray* resultsForID = [result objectForKey:anID];
if (!resultsForID)
{
resultsForID = [NSMutableArray array];
[result setObject:resultsForID forKey:anID];
}
[resultsForID addObject:dict];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With