Создайте структурированный NSDictionary из NSArray - PullRequest
0 голосов
/ 03 марта 2012

Мне нужно создать структурированный 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];
    }

}

1 Ответ

1 голос
/ 03 марта 2012

Кажется, единственный способ достичь желаемого - это серия вложенных циклов (для каждого уровня: раздел, категория, дата).В самом внутреннем цикле вы создаете сложный предикат, подобный этому:

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];
}
...