我需要创建一个带有分组键的结构化NSDictionary
,从NSArray
开始
这是一个例子:
[
{
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
}
]
结果应该是这样的NSDictionary
(我没有检查过值是否合适,我只是想提出这个想法):
[
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;
}]
}
}
]
我可以使用NSPredicate
或键值编码实现此目的,并避免多次循环吗?
我建议的解决方案
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];
}
}
答案 0 :(得分:1)
似乎你可以实现你想要的唯一方法是一系列嵌套的for循环(对于每个级别:section,category,date)。在最里面的循环中,您可以创建一个复杂的谓词:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"section = %@ AND category = %@ AND date = %@",
section, category, date];
然后,您过滤掉输入数组,并仅使用key1
和key2
构建新的字典数组。您可以将此日期数组添加到给定日期的类别字典中,然后将类别字典添加到给定类别的输出字典中。我没有看到任何更简单的方法。
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];
}