Reputation: 5525
As a concrete example, suppose I have the following array of dictionaries, which share the same keys and value types:
[ {car: "Ferrari", make: "Italian", color: "red"},
{car: "Ferrari", make: "Italian", color: "yellow"},
{car: "Porsche", make: "German", color: "green"},
{car: "Porsche", make: "German", color: "silver"}
]
How would I be able to search only by a key (for example, by "car") through the dictionaries, and then combine the values that are different (in this case, the "color") as arrays, so that my resultant array is:
[ {car: "Ferrari", make: "Italian", color: ["red", "yellow"]},
{car: "Porsche", make: "German", color: ["green", "silver"]},
]
Thanks!
Upvotes: 0
Views: 590
Reputation: 918
Here is my approach with a little better time complexity. The first function convertDataBasedOnKey
will receive the value from which you may want to compare, as you said on the question you wanted to be searchable by a key. The second function getSharedDictionaryOfElements
is just for creating the final dictionary with the values merged.
- (void)convertDataBasedOnKey:(NSString *)baseKey {
desiredFormatData = [[NSMutableArray alloc] init];
NSMutableString *filterString = [NSMutableString stringWithFormat:@"(%@ ==",baseKey];
[filterString appendString:@" %@)"];
while (currentFormatData.count != 0) {
NSDictionary *aDictionary = [currentFormatData firstObject];
NSString *firstValue = [aDictionary objectForKey:baseKey];
NSArray *filtered = [currentFormatData filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:filterString, firstValue]];
NSDictionary *mergedDictionary = [self getSharedDictionaryOfElements:filtered sharingValueForKey:baseKey];
[desiredFormatData addObject:mergedDictionary];
[currentFormatData removeObjectsInArray:filtered];
}
NSLog(@"%@",desiredFormatData.description);
}
- (NSDictionary *)getSharedDictionaryOfElements:(NSArray *)anArray sharingValueForKey:(NSString *)aKey {
if (!anArray || anArray.count == 0) {
return nil;
}
// As all the elements in anArray share the same keys
NSMutableDictionary *resultDictionary = [[NSMutableDictionary alloc] init];
NSDictionary *modelDictionary = [anArray firstObject];
for (NSString *aKey in modelDictionary.allKeys) {
NSPredicate *filterByKey = [NSPredicate predicateWithValue:YES];
NSArray *resultArray = [[anArray valueForKey:aKey] filteredArrayUsingPredicate:filterByKey];
NSMutableArray *uniqueArray = [NSMutableArray arrayWithArray:[[NSSet setWithArray:resultArray] allObjects]];
[resultDictionary setObject:uniqueArray forKey:aKey];
}
return resultDictionary;
}
Example
Using this two functions to obtain what you asked will be something like this:
Having declared this two variables:
NSMutableArray *currentFormatData;
NSMutableArray *desiredFormatData;
Then filling the first one with the example data and making the operation based on a key "car":
currentFormatData = [NSMutableArray arrayWithArray:@[@{@"car":@"Ferrari", @"make":@"Italian", @"color":@"red"},
@{@"car":@"Ferrari", @"make":@"Italian", @"color":@"yellow"},
@{@"car":@"Porsche", @"make":@"German", @"color":@"green"},
@{@"car":@"Porsche", @"make":@"German", @"color":@"silver"}]];
[self convertDataBasedOnKey:@"car"];
Upvotes: 1
Reputation: 7935
The following method will solve your problem:
- (NSArray*) combineValuesFromArray:(NSArray*) array byKey: (NSString*) key
{
NSMutableSet *differentValues = [NSMutableSet set];
for(NSDictionary *dict in array)
{
[differentValues addObject:dict[key]];
}
NSMutableArray *result = [NSMutableArray array];
for(NSString *value in differentValues)
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", key, value];
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicate];
NSMutableDictionary *sets = [NSMutableDictionary new];
for(NSDictionary *dict in filteredArray)
{
for(NSString *dictKey in dict)
{
NSMutableSet *set = [sets[dictKey] mutableCopy];
if(set == nil) set = [NSMutableSet new];
[set addObject:dict[dictKey]];
sets[dictKey] = set;
}
}
NSMutableDictionary *newDict = [NSMutableDictionary new];
for(NSString *dictKey in sets)
{
newDict[dictKey] = ([sets[dictKey] count] == 1) ? [sets[dictKey] anyObject] : [sets[dictKey] copy];
}
[result addObject:[newDict copy]];
}
return [result copy];
}
I've used following code for testing:
NSString *car = @"car";
NSString *make = @"make";
NSString *color = @"color";
NSArray *array = @[ @{car: @"Ferrari", make: @"Italian", color: @"red"},
@{car: @"Ferrari", make: @"Italian", color: @"yellow"},
@{car: @"Porsche", make: @"German", color: @"green"},
@{car: @"Porsche", make: @"German", color: @"silver"}
];
NSLog(@"%@", [self combineValuesFromArray:array byKey:car]);
Upvotes: 1