2010-12-15 2 views
7

У меня есть два массива: NSMutableArray и NSArray. NSMutableArray является «хранилищем», он хранит результаты из источника NSArrays. Каждые 5 минут появляется новый NSArray, и данные необходимо фильтровать и сортировать.Слияние NSMutableArray с NSArray, фильтрация дубликатов

Сортировка по дате довольно проста, поэтому мне удалось получить NSArray, отсортированный по NSDate. Сортировка другого массива не требуется, так как это может вызвать путаницу с пользователем.

Что я хочу сделать: NSArray имеет много разных объектов, на которые все отвечают - [имя объекта], возвращая NSString. NSArray необходимо объединить в NSMutableArray, добавив только объектов.

Слияние само по себе не проблема, но производительность. NSMutableArray может содержать до 3000 элементов, а NSArray может содержать до 250 элементов, хотя обычно только 5 или 6 из них должны быть объединены в NSMutableArray.

Итак, мой вопрос: как вы объедините два массива в Objective-C, фильтруя дубликаты, без повторения (250 * 3000) раз?

Том

Edited уточнить что-то
В «дублируют» объекты являются объектами, которые являются дубликатом для пользователя, но не в коде. Они имеют то же имя, но не тот же адрес.

Более уточнение: @"value" != @"value" // true

ответ

10

Есть name свойство объектов, хранящихся в массивах? Если это так, вы можете использовать довольно простой NSPredicate для фильтрации неизменяемого массива, прежде чем добавлять результаты к изменяемому. Вот пример:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NONE name == %@.name", mutableArray]; 
resultsArray = [immutableArray filteredArrayUsingPredicate:predicate]; 
[mutableArray addObjectsFromArray:immutableArray]; 
0

Edited удалить некоторые тупость (слева много, хотя)

Несколько вариантов:

  1. Удалить все соответствующие объекты из NSMutableArray с помощью removeObjectIdenticalTo , Это требует итерации через меньший массив, но, как вы заметили, они обычно небольшие. Затем

  2. Добавить все элементы из нового массива, используя addObjectsFromArray

Или ... ну, это на самом деле может быть быстрее, вместо этого:

  1. перебирать новый массив ищет совпадения с indexOfObjectIdenticalTo, используя addObject для добавления в несоответствующие объекты.

Дорогостоящий в любом случае, но выполнимый.

+0

Это не будет делать то, что мне нужно: объекты не являются идентичными, только Значение `- [имя объекта]` равно – 2010-12-15 21:36:45

0

Вы можете использовать NSSet и NSMutableSet? Это может помочь решить проблему дубликатов.

Edit:

на основе ваших комментариев, вы можете использовать NSSet для проверки членства объекта быстро, в дополнение к массиву.Это потребует немного больше памяти, но если вы не против, это может позволить вам быстро проверить. У вас будет ваш резервный магазин NSMutableArray, а затем NSSet, чтобы отслеживать принадлежность объекта. Вы сохранили бы инвариант, что NSMutableArray не содержит дубликатов. Вы можете использовать такой код:

// Assume that arrayStore is an NSMutableArray * instance variable 
// Also, storeSet is an NSMutableSet * ivar 

- (void)addObjectsFromArray:(NSArray *)data 
{ 
    for (id item in data) { 
     if (![storeSet member:item]) { 
      // Will have to keep arrayStore sorted somehow 
      [arrayStore addObject:item]; 
      [storeSet addObject:item]; 
     } 
    } 
} 

Вы только должны перебирать NSArray. Я не уверен, как NSSet реализована с моей головы, но проверка членства не будет такой операцией O (n), как для несортированного массива.

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

+0

NSSet 1) Unordered и 2) работает только для добавления одного и того же объекта дважды. NSSet не видит два одинаковых объекта с разными адресами. – 2010-12-15 21:40:51

+1

@Tom van der Woerdt: Устанавливает использование `isEqual` для сравнения объектов, поэтому, если ваш класс переопределяет` isEqual`, вы можете сравнивать на основе чего-то другого, кроме местоположения памяти. Кроме того, набор неупорядочен, но вы можете повернуть набор в массив и отсортировать его по мере необходимости (если вам не нужно его сортировать все время). – mipadi 2010-12-15 21:51:35

+0

О, я не знал о части `isEqual`, звучит хорошо. Однако, да, их нужно сортировать все время. – 2010-12-15 21:55:37

0

Я бы, вероятно, начал с создания нового изменяемого массива, который содержит содержимое вашего NSMutableArray и NSArray. Затем отсортируйте новый массив на основе свойства name и затем запустите массив один раз, вытаскивая только уникальные элементы.

+0

Я думаю, что немного (!) Уменьшит количество необходимых вычислений, да, но NSMutableArray должен оставаться тем же и добавлять только новые объекты. – 2010-12-15 21:57:19

+0

На самом деле сокращение числа вычислений было бы довольно драматичным. От 3000 * 250 = 750 000 вычислений вы бы пошли до ~ 40 000 ... это почти на два порядка. Метод предиката более чист, но я сомневаюсь, что он будет намного быстрее. Вероятно, вы могли бы немного улучшить ситуацию, если бы вы написали свой собственный алгоритм сортировки, который мог бы удалить элемент из рассмотрения, когда он сравнивал два элемента, которые были эквивалентны. – ericg 2010-12-15 22:09:00

0

Есть, вероятно, много способов, чтобы значительно повысить производительность, но, чтобы быть в состоянии предложить любой, мы действительно должны знать больше о том, что объекты в массивах «являются»: то, что они представляют ? Как они используются? (Так, например, являются элементы в массиве хранилища отображается в виде таблицы?)

NSMutableDictionary, NSMutableSet и т.д. может быть объединен с NSMutableArray организовать и реализовать модель в эффективном образе.

Например, предположим, что мы знаем, что объект представляет человека: MDPerson. У человека есть пол, дата рождения, имя, уникальный идентификатор и набор атрибутов, которые могут измениться. Учитывая это более высокое понимание того, что представляет объект, мы знаем, что 2 человека равны, только если их уникальные идентификаторы одинаковы (другими словами, 2 разных человека могут иметь одинаковое имя, пол и дату рождения). Предположим, что ваш главный NSMutableArray составлен из списка из 3000 человек. Входящий массив состоит из 500 человек, которые уже находятся в главном NSMutableArray. Некоторые из этих 500 человек могут иметь «обновленные» атрибуты, а это значит, что их экземпляр в основном массиве должен быть обновлен этой информацией.

Учитывая это понимание, ясно, что основной список должен быть реализован как NSMutableDictionary, а не NSMutableArray. В словаре единственным ключом будет уникальный идентификатор человека, и его экземпляр для лица будет значением для ключа. Вы могли бы затем цикл через входящий массив из 500 человек только один раз:

// main dictionary is called personIDsAndPersons 

for (MDPerson *person in incomingPersons) { 
     MDPerson *existingPerson = [personIDsAndPersons objectForKey:[person uniqueID]]; 
     // if nil, the person doesn't exist 
     if (existingPerson) { 
      // update the existing person's attributes 
      [existingPerson setUniqueAttributes:[person uniqueAttributes]]; 
     } 
} 

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

Вы упомянули, что 2 предмета являются одинаковыми, если они имеют одинаковое имя. Значит ли это, что каждый элемент в основном массиве из 3000 объектов имеет уникальное имя? Если это так, вы можете использовать NSMutableDictionary, чтобы обеспечить эффективный доступ к объектам, указав ключи в словаре как имя, а значения - экземпляр объекта.Затем вы можете использовать отдельный NSMutableArray, который используется только для целей показа: он позволяет упорядоченную, отсортированную организацию тех же объектов, которые хранятся в NSMutableDictionary. Помните, что когда вы добавляете объект в массив или словарь, обычно вы не создаете новую копию, вы просто сохраняете существующий объект.

5

Как об этом:

[mutable removeObjectsInArray:newArray]; 
[mutable addObjectsFromArray:newArray]; 

Это не жирное, но легко реализовать :)

Смежные вопросы