Фильтрация NSDictionary массивов с использованием NSPredicate - PullRequest
1 голос
/ 28 января 2011

У меня есть список, который я определил как словарь, который содержит много массивов. Я хотел бы вытащить из этого словаря все массивы, у которых есть первый «Item 0» (Соглашение об именах по умолчанию), который соответствует данной строке.

Я пробовал что-то похожее на Filtering NSArray, но я получаю ошибку регулярного выражения, и консоль выдает содержимое первого массива в словаре.

Кроме того, нужно ли мне создавать экземпляр моего NSDictionary как NSMutableDictionary, так как я буду выполнять процесс фильтрации на нем? Что лучше сделать, чтобы скопировать прочитанный NSDictionary из plist в mustable, а затем выполнить работу над ним?

Ответы [ 2 ]

9 голосов
/ 28 января 2011

Это возможно, но окольным путем. Я рекомендую вам рассмотреть возможность использования другого подхода.

Как говорится, вот как вы это сделаете:

NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:
                   [NSArray arrayWithObjects:@"a", @"b", @"c", nil], @"a",
                   [NSArray arrayWithObjects:@"b", @"c", @"a", nil], @"b",
                   [NSArray arrayWithObjects:@"c", @"a", @"b", nil], @"c",
                   [NSArray arrayWithObjects:@"a", @"b", @"c", nil], @"d",
                   nil];
NSPredicate *p = [NSPredicate predicateWithFormat:@"%@[SELF][0] == 'a'", d];
NSLog(@"%@", p);
NSArray *keys = [d allKeys];
NSArray *filteredKeys = [keys filteredArrayUsingPredicate:p];
NSLog(@"%@", filteredKeys);
NSDictionary *matchingDictionary = [d dictionaryWithValuesForKeys:filteredKeys];
NSLog(@"%@", matchingDictionary);

Вот что происходит:

У нас есть исходный словарь, d. Это словарь, в котором буква (a, b, c или d) связана с массивом. Мы собираемся найти все ключи , которые соответствуют массиву, где первый элемент - a.

Наш предикат:

[NSPredicate predicateWithFormat:@"%@[SELF][0] == 'a'", d];

Здесь мы используем оператор индексации в нашем исходном словаре. SELF при оценке этого предиката будет одним из ключей из d. Так что %@[SELF] вернет массив. Затем мы берем 0-й элемент этого массива и сравниваем его со строкой a. Если это соответствует, то это возвращает YES.

Затем мы берем все ключи в словаре и фильтруем их, используя этот предикат. Это означает, что результирующий массив будет содержать только ключи, где первый элемент соответствующего массива равен a.

Как только у нас есть соответствующие ключи, мы извлекаем «подсловарь» из нашего исходного словаря, чтобы получить наш окончательный сокращенный словарь.

В приведенном выше тесте matchingDictionary имеет два ключа (a и d), которые оба связаны с массивом, содержащим (a, b, c).

Если вы хотите вместо NSArray, который содержит совпадающие массивы, вы бы использовали -[NSDictionary objectsForKeys:notFoundMarker:] вместо.

Однако это неудобное решение, и я все еще думаю, что вам следует реорганизовать ваши данные.

2 голосов
/ 28 января 2011

Я почти уверен, что вы не можете использовать NSPredicate здесь (хотя, если вы захотите использовать NSPredicate для массивов в NSDictionary , вы можете),Тем не менее, есть вполне приемлемая альтернатива, как показано в следующем примере:

NSMutableArray* filteredArrays = [[NSMutableArray alloc] init];
for (NSString* currentKey in myDictionaryOfArrays)
{
    NSArray* currentArray = [myDictionaryOfArrays objectForKey:currentKey];
    NSString* objectAtFirstIndex = [currentArray objectAtIndex:0];
    if ([objectAtFirstIndex isEqualTo:mySearchString]);
    {
        [filteredArrays addObject:currentArray];
    }
}

Кстати, оператор fast enumuration ("for each") следует использовать, потому что из него можно получить повышение производительности.

То, что у вас осталось, - это изменяемый массив массивов, которые соответствуют вашим критериям поиска.Если вы хотите быть немного более аккуратным (например, если этот код формирует метод), вы можете преобразовать его в неизменяемый массив (если, конечно, вы не хотите продолжать вносить изменения).

NSArray* filteredResults = [NSArray arrayWithArray:filteredArrays];
...