Reputation: 11543
I need to create a structured NSDictionary
with grouped keys, starting from a NSArray
.
This is an example:
[
{
section = section1,
category = category1,
date = 2011-12-01,
key1 = foo,
key2 = bar
},
{
section = section1,
category = category2,
date = 2011-12-01,
key1 = foo,
key2 = bar
},
{
section = section1,
category = category2,
date = 2011-12-03
key1 = foo,
key2 = bar
},
{
section = section2,
category = category1,
date = 2011-12-03
key1 = foo,
key2 = bar
}
]
The result should be a NSDictionary
like this (I didn't checked that the values are ok, I just want to give the idea):
[
section1 = {
category1 = {
2011-12-01 =
[{
key1 = foo;
key2 = bar;
},
{
key1 = foo;
key2 = bar;
}
]
}
},
category2 = {
2011-12-01 =
[{
key1 = foo;
key2 = bar;
}],
}
},
section2 = {
category1 = {
2011-12-01 =
[{
key1 = foo;
key2 = bar;
}]
}
}
]
Can I achieve this using NSPredicate
or Key-Value Coding, and avoid many loops?
My proposed solution
NSMutableDictionary *sectionEmpty = [NSMutableDictionary dictionary];
NSArray *values = [records allValues];
NSArray *sections = [[records allValues] valueForKeyPath:@"@distinctUnionOfObjects.section"];
for(NSString *section in sections) {
// Find records for section
NSArray *sectionRecords = [values filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"section == %@",section]];
// Find unique categories
NSArray *categorys = [sectionRecords valueForKeyPath:@"@distinctUnionOfObjects.category"];
// Loop through categories
for (NSString *category in categorys) {
// Creating temporary record
NSMutableDictionary *empty = [NSMutableDictionary dictionary];
// Find records for category
NSArray *categoryRecords = [sectionRecords filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"category == %@",category]];
// Find unique dates
NSArray *dates = [categoryRecords valueForKeyPath:@"@distinctUnionOfObjects.date"];
// Loop through dates
for (NSString *date in dates) {
// Creating temporary record
NSMutableDictionary *emptyDate = [NSMutableDictionary dictionary];
// Find records for dates
NSArray *dateRecords = [categoryRecords filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"date == %@",date]];
// Split date
NSString *dateString = [[date componentsSeparatedByString:@" "] objectAtIndex:0];
// Check if date exist in temporary record
if(![[emptyDate allKeys] containsObject:dateString]){
[emptyDate setObject:[NSMutableArray array] forKey:dateString];
}
// Set date records for date key
[[emptyDate objectForKey:dateString] addObject:dateRecords];
// Set date for category
[empty setObject:emptyDate forKey:category];
}
// Set category for section
[sectionEmpty setObject:empty forKey:section];
}
}
Upvotes: 0
Views: 1845
Reputation: 3835
It seems the only way you can achieve what you want is a series of nested for loops (for each level: section, category, date). In the innermost loop you create a complex predicate like this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"section = %@ AND category = %@ AND date = %@",
section, category, date];
Then you filter out the input array, and construct new array of dictionaries with key1
and key2
only. You add this dates array to categories dictionary for a given date, and then you add a categories dictionary to the output dictionary for a given category. I don't see any simpler way of doing this.
NSArray *input = [records allValues];
NSMutableDictionary *output = [NSMutableDictionary dictionary];
NSArray *sections = [NSArray valueForKeyPath:@"@distinctUnionOfObjects.section"];
NSArray *categories = [NSArray valueForKeyPath:@"@distinctUnionOfObjects.category"];
NSArray *dates = [NSArray valueForKeyPath:@"@distinctUnionOfObjects.date"];
NSPredicate *predicate;
for (NSString *section in sections) {
NSMutableDictionary *categoriesDictionary = [NSMutableDictionary dictionary];
for (NSString *category in categories) {
NSMutableArray *datesArray = [NSMutableArray array];
for (NSString *date in dates) {
predicate = [NSPredicate predicateWithFormat:
@"section = %@ AND category = %@ AND date = %@",
section, category, date];
NSArray *filteredInput = [input filteredArrayUsingPredicate:predicate];
if (filteredInput.count > 0) {
NSMutableArray *filteredOutput = [NSMutableArray arrayWithCapacity:filteredInput.count];
[filteredInput enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[filteredOutput addObject:
[NSDictionary dictionaryWithObjectsAndKeys:
[obj objectForKey:@"key1"], @"key1",
[obj objectForKey:@"key2"], @"key2", nil]
];
}];
if (filteredOutput.count > 0)
[datesArray addObject:filteredOutput];
}
}
if (datesArray.count > 0)
[categoriesDictionary setObject:datesArray forKey:category];
}
if (categoriesDictionary.count > 0)
[output setObject:categoriesDictionary forKey:section];
}
Upvotes: 1