Что более эффективно при создании нового массива в Python или при манипуляциях с массивами на месте? - PullRequest
2 голосов
/ 14 ноября 2009

Скажем, у меня есть массив с парой сотен элементов. Мне нужно перебрать массив и заменить один или несколько элементов в массиве другим элементом. Какая стратегия более эффективна в питоне с точки зрения скорости (меня не беспокоит память)?

Например: у меня есть массив

 my_array = [1,2,3,4,5,6]

Я хочу заменить первые 3 элемента одним элементом со значением 123.

Вариант 1 (встроенный):

my_array = [1,2,3,4,5,6]
my_array.remove(0,3)
my_array.insert(0,123)

Option2 (создание нового массива):

my_array = [1,2,3,4,5,6]
my_array = my_array[3:]    
my_array.insert(0,123)

Обе вышеперечисленные опции будут давать результат:

>>> [123,4,5,6]

Любые комментарии будут оценены. Особенно, если есть варианты, которые я пропустил.

Ответы [ 4 ]

6 голосов
/ 14 ноября 2009

Если вы хотите заменить элемент или набор элементов в списке, вы никогда не должны использовать свой первый вариант. Удаление и добавление в список в середине происходит медленно ( ссылка ). Ваш второй вариант также довольно неэффективен, так как вы выполняете две операции для одной замены.

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

>>> my_array = [1,2,3,4,5,6]
>>> my_array[:3] = [123]
>>> my_array
[123, 4, 5, 6]
3 голосов
/ 14 ноября 2009
arr[0] = x

заменяет 0-й элемент на x. Вы также можете заменить целые ломтики.

>>> arr = [1, 2, 3, 4, 5, 6]
>>> arr[0:3] = [8, 9, 99]
>>> arr
[8, 9, 99, 4, 5, 6]
>>> 

И вообще неясно, чего вы пытаетесь достичь. Пожалуйста, предоставьте больше информации или пример.


ОК, что касается вашего обновления. Метод remove не работает (для удаления требуется один аргумент). Но нарезка, которую я представил, работает и для вашего случая:

>>> arr
[8, 9, 99, 4, 5, 6]
>>> arr[0:3] = [4]
>>> arr
[4, 4, 5, 6]

Я думаю, это самый быстрый метод, но попробуйте его с timeit. Согласно моим тестам, это в два раза быстрее, чем ваш подход "новый массив".

0 голосов
/ 14 ноября 2009

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

Как вы узнаете, когда у вас есть последовательность предметов, которые необходимо заменить? Я предполагаю, что у вас есть такая функция:

def replacement(objects, startIndex):
    "returns a pair (numberOfObjectsToReplace, replacementObject), or None if the should be no replacement"

Я бы тогда сделал:

def replaceAll(objects):
    src = 0
    dst = 0
    while (src < len(objects)):
        replacementInfo = replacement(objects, src)
        if (replacementInfo != None):
            numberOfObjectsToReplace, replacementObject = replacementInfo
        else:
            numberOfObjectsToReplace = 1
            replacementObject = objects[src]
        objects[dst] = replacementObject
        src = src + numberOfObjectsToReplace
        dst = dst + 1
    del objects[dst:]

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

0 голосов
/ 14 ноября 2009

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

>>> import array
>>> my_array = array.array('i', [1,2,3,4,5,6])
>>> my_array = my_array[3:]
>>> my_array.insert(0,123)
>>> my_array
array('i', [123, 4, 5, 6])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...