Лучший способ удалить из NSMutableArray при итерации?

PostgreSQL не определяет round(double precision, integer). По причинам, которые @Catcall объясняет в комментариях, версия раунда, которая принимает точность, доступна только для numeric.

regress=> SELECT round( float8 '3.1415927', 2 );
ERROR:  function round(double precision, integer) does not exist

regress=> \df *round*
                           List of functions
   Schema   |  Name  | Result data type | Argument data types |  Type  
------------+--------+------------------+---------------------+--------
 pg_catalog | dround | double precision | double precision    | normal
 pg_catalog | round  | double precision | double precision    | normal
 pg_catalog | round  | numeric          | numeric             | normal
 pg_catalog | round  | numeric          | numeric, integer    | normal
(4 rows)

regress=> SELECT round( CAST(float8 '3.1415927' as numeric), 2);
 round 
-------
  3.14
(1 row)

(В приведенном выше примечании обратите внимание, что float8 является просто сокращенным псевдонимом для double precision. Вы можете видеть, что PostgreSQL расширяет его на выходе).

Вы должны указать значение, округленное до numeric, для использования двухфакторной формы round. Просто добавьте ::numeric для стенографического броска, например round(val::numeric,2).


Если вы форматируете для отображения пользователю, не используйте round. Используйте to_char (см. функции форматирования типа данных в руководстве), который позволяет указать формат и дает результат text, на который не влияет какая бы странность, на которую может повлиять ваш язык клиента с значениями numeric. Например:

regress=> SELECT to_char(float8 '3.1415927', 'FM999999999.00');
    to_char    
---------------
 3.14
(1 row)

to_char будет округлять числа для вас как часть форматирования. Префикс FM сообщает to_char, что вы не хотите добавлять пробелы с ведущими пробелами.

194
задан Ned Batchelder 10 November 2008 в 02:55
поделиться

12 ответов

Для ясности мне нравится делать начальный цикл, где я собираю объекты для удаления. Тогда я удаляю их. Вот является демонстрационный Objective C использования 2,0 синтаксисами:

NSMutableArray *discardedItems = [NSMutableArray array];

for (SomeObjectClass *item in originalArrayOfItems) {
    if ([item shouldBeDiscarded])
        [discardedItems addObject:item];
}

[originalArrayOfItems removeObjectsInArray:discardedItems];

Тогда нет никакого вопроса о том, обновляются ли индексы правильно, или другие небольшие бухгалтерские детали.

Отредактированный для добавления:

было отмечено в других ответах, что обратная формулировка должна быть быстрее. т.е. Если Вы выполняете итерации через массив и составляете новый массив объектов оставаться вместо объектов отбросить. Это может быть верно (хотя что относительно памяти и стоимости обработки выделения нового массива и отбрасывания старого?), но даже если бы это быстрее, это не может быть столь же большое соглашение, как это было бы для наивной реализации, потому что NSArrays не ведут себя как "нормальные" массивы. Они говорят разговор, но они обходят различный обход. Посмотрите хороший анализ здесь:

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

Для меня сообщение взятия домой должно использовать любую формулировку, является самым ясным Вам. Оптимизируйте только если необходимый. Я лично нахожу вышеупомянутую формулировку самой ясной, который является, почему я использую ее. Но если обратная формулировка более ясна Вам, пойдите для нее.

386
ответ дан vellvisher 4 November 2019 в 14:56
поделиться

Если все объекты в Вашем массиве уникальны, или Вы хотите удалить все случаи объекта, когда найдено, Вы могли быстро перечислить на копии массива и использовании [NSMutableArray removeObject:] для удаления объекта из оригинала.

NSMutableArray *myArray;
NSArray *myArrayCopy = [NSArray arrayWithArray:myArray];

for (NSObject *anObject in myArrayCopy) {
    if (shouldRemove(anObject)) {
        [myArray removeObject:anObject];
    }
}
1
ответ дан lajos 4 November 2019 в 14:56
поделиться

Как насчет того, чтобы подкачать элементы Вы хотите удалить с 'n'th элемент, 'n-1'th элемент и так далее?

, Когда Вы сделаны, Вы изменяете размеры массива к 'предыдущему размеру - количество подкачек

1
ответ дан Cyber Oliveira 4 November 2019 в 14:56
поделиться

Почему Вы не добавляете объекты, которые будут удалены в другой NSMutableArray. Когда Вы закончены, выполнив итерации, можно удалить объекты, которые Вы собрали.

1
ответ дан Paul Croarkin 4 November 2019 в 14:56
поделиться

это должно сделать это:

    NSMutableArray* myArray = ....;

    int i;
    for(i=0; i<[myArray count]; i++) {
        id element = [myArray objectAtIndex:i];
        if(element == ...) {
            [myArray removeObjectAtIndex:i];
            i--;
        }
    }

надежда это помогает...

5
ответ дан Pokot0 4 November 2019 в 14:56
поделиться

Добавьте объекты, которые Вы хотите удалить к второму массиву и, после цикла, использовать-removeObjectsInArray:.

5
ответ дан Nathan Kinsinger 4 November 2019 в 14:56
поделиться

Более декларативным способом, в зависимости от критериев, соответствующих объектам для удаления Вас, мог использовать:

[theArray filterUsingPredicate:aPredicate]

@Nathan должен быть очень эффективен

8
ответ дан elp 4 November 2019 в 14:56
поделиться

Любой цикл использования, считающий в обратном порядке по индексам:

for (NSInteger i = array.count - 1; i >= 0; --i) {

или делают копию с объектами, которые Вы хотите сохранить.

, В частности, не используйте for (id object in array) цикл или NSEnumerator.

17
ответ дан pkamb 4 November 2019 в 14:56
поделиться

Можно использовать NSpredicate для удаления объектов из изменяемого массива. Это требует не для циклов.

, Например, если у Вас есть NSMutableArray имен, можно создать предикат как этот:

NSPredicate *caseInsensitiveBNames = 
[NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];

следующая строка оставит Вас с массивом, который содержит только имена, запускающиеся с b.

[namesArray filterUsingPredicate:caseInsensitiveBNames];

при наличии затруднений при создании предикатов Вы нуждаетесь, используете этот ссылка разработчика яблока .

28
ответ дан 4 November 2019 в 14:56
поделиться

Некоторые из других ответов имели бы низкую производительность на очень больших массивах, потому что методы как removeObject: и removeObjectsInArray: включают выполнение линейного поиска получателя, который является отходами, потому что Вы уже знаете, где объект. Кроме того, любой вызов к removeObjectAtIndex: должен будет скопировать значения с индекса до конца массива одним слотом за один раз.

более эффективный было бы следующим:

NSMutableArray *array = ...
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]];
for (id object in array) {
    if (! shouldRemove(object)) {
        [itemsToKeep addObject:object];
    }
}
[array setArray:itemsToKeep];

, поскольку мы устанавливаем способность itemsToKeep, мы не тратим впустую значений копирования времени во время изменения размеры. Мы не изменяем массив на месте, таким образом, мы свободны использовать Быстрое Перечисление. Используя setArray: для замены содержания array с itemsToKeep будет эффективно. В зависимости от Вашего кода Вы могли даже заменить последнюю строку:

[array release];
array = [itemsToKeep retain];

, Таким образом, нет даже потребности скопировать значения, только подкачайте указатель.

39
ответ дан benzado 4 November 2019 в 14:56
поделиться

One more variation. So you get readability and good performace:

NSMutableIndexSet *discardedItems = [NSMutableIndexSet indexSet];
SomeObjectClass *item;
NSUInteger index = 0;

for (item in originalArrayOfItems) {
    if ([item shouldBeDiscarded])
        [discardedItems addIndex:index];
    index++;
}

[originalArrayOfItems removeObjectsAtIndexes:discardedItems];
82
ответ дан 23 November 2019 в 05:22
поделиться

Ответ Benzado выше - что делать для преформ. В одном из моих приложений removeObjectsInArray занял 1 минуту, простое добавление в новый массив заняло 0,023 секунды.

1
ответ дан 23 November 2019 в 05:22
поделиться