Лучшая альтернатива для проверки существования ключа NSDictionary в NSArray? - PullRequest
2 голосов
/ 16 февраля 2010

У меня есть NSArray из NSDictionaries. Мне нужно проверить, есть ли хотя бы одно вхождение объекта для ключа NSDictionary в NSArray. Я делаю это с помощью

int i;
for (i=0;i< [myArray count];i++)
{
    if ([[[myArray objectAtIndex: i] objectForKey: myKey] isEqualToString: myString]) {
        found = YES;
        break;
    } else {
        found = NO;
    }
}

Но у меня есть подозрение, что есть лучшая / более быстрая альтернатива ...

Спасибо

Ответы [ 7 ]

7 голосов
/ 16 февраля 2010

Да. Используйте «быстрое перечисление», также известное как for-in loop:

for (NSDictionary* dict in myArray) {

Также для сравнения NSString используйте -isEqualToString:.

   if ([[dict objectForKey: myKey] isEqualToString:myString]) {

Тем не менее, здесь нет алгоритмического улучшения (т. Е. Этот метод уже лучший)

6 голосов
/ 16 февраля 2010

Это так быстро, как вы можете получить это с вашими текущими структурами данных. Вы делаете O (1) поиск для каждого словаря в массиве. Если у вас огромное количество словарей, это может дорого обойтись, поэтому вы можете рассмотреть (в значительной степени зависит от семантики ваших данных) сохранение отдельного внешнего NSSet, который содержит набор строковых объектов, содержащих все значения в словарях. Затем вы можете проверить один раз в этом наборе на существование.

Расскажите подробнее о форме данных для более глубокого понимания ...

Также будьте осторожны с оператором == с NSString с. Если вы на самом деле проверяете, равен ли текст строки, вы должны использовать -isEqualToString: вместо этого, так как ваша форма просто сделает сравнение ссылок.

5 голосов
/ 17 февраля 2010

Вы должны использовать быстрое перечисление, которое будет перебирать объекты, используя массив C за кулисами. Прямо сейчас вы вызываете оба -objectAtIndex: и -count каждый раз в цикле.

Вы также можете проверить NSPredicate, если myKey является строкой. Моя интуиция говорит мне, что это будет медленнее, но вы никогда не знаете, выиграет ли это от внутренней оптимизации для NSDictionary:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ LIKE %@", myKey, myString];
BOOL found = ([[myArray filteredArrayUsingPredicate:predicate] count] > 0);
3 голосов
/ 17 февраля 2010

Вы можете быть намного более лаконичны с кодированием значения ключа:

[[myArray valueForKey:myKey] containsObject:myString];

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

2 голосов
/ 16 февраля 2010

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

Вы можете использовать «быстрое перечисление», чтобы немного упростить вещи:

bool found = NO;

for (NSDictionary *dict in myArray) {
    found = [[dict objectForKey:myKey] isEqualToString:myString];

    if (found)
        break;
}

Это только «быстрее» в том смысле, что меньше слов писать; Скорость исполнения одинакова.

1 голос
/ 03 октября 2014

После получения вашего объекта, вы можете проверить, что ваш полученный объект "NSArray" или "NSDictionary" или "NSString" и т. Д. Вы можете использовать следующий код для проверки вашего объекта.

if([obj isKindOfClass:[NSArray class]]){
    NSLog(@"IS NSArray");
}
else if([obj isKindOfClass:[NSDictionary class]]){
    NSLog(@"Is NSDictionary");
}
else
{
    NSLog(@"Other");
}
0 голосов
/ 28 сентября 2016

С быстрым перечислением

BOOL found;

for (NSDictionary *dict in array) {

        if ([[dict objectForKey:@"YOURKEY"] isEqualToString:@"YOURVALUE"]) {
            found = YES;
            break;
        } else {
            found = NO;
        }
    }
...