поиск и замена элементов в списке


273

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

Например, предположим, что мой список имеет следующие целые числа

>>> a = [1,2,3,4,5,1,2,3,4,5,1]

и мне нужно заменить все вхождения числа 1 значением 10, поэтому мне нужен выход

>>> a = [10, 2, 3, 4, 5, 10, 2, 3, 4, 5, 10]

Таким образом, моя цель - заменить все экземпляры числа 1 числом 10.


11
Кстати, для чего это?
— 2010 г.

Ответы:


250
>>> a= [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1]
>>> for n, i in enumerate(a):
...   if i == 1:
...      a[n] = 10
...
>>> a
[10, 2, 3, 4, 5, 10, 2, 3, 4, 5, 10]

15
Это плохое и очень непитонное решение. Подумайте об использовании списка понимания.
— AdHominem

205
Это прекрасное, но очень непитонное решение. Подумайте об использовании списка понимания.
— Жан-Франсуа Корбетт

Подумайте об использовании списка, например, @outis ниже!
— AMC

6
Это работает лучше, чем понимание списка, не так ли? Он производит обновления на месте вместо создания нового списка.
— neverendingqs

@neverendingqs: Нет. Работа над переводчиком доминирует над операцией, и понимание имеет меньше. Понимание работает немного лучше, особенно с большей долей элементов, проходящих условие замены. Имейте некоторое время: ideone.com/ZrCy6z
— user2357112 поддерживает Monica

519

Попробуйте использовать понимание списка и троичный оператор .

>>> a=[1,2,3,1,3,2,1,1]
>>> [4 if x==1 else x for x in a]
[4, 2, 3, 4, 3, 2, 4, 4]

9
Но это не изменится, aправда? Я думаю, что OP хотел aизмениться
— Dula

10
@Dula, вы можете сделать a = [4, если x == 1, иначе x для x в a], это повлияет на a
— Alekhya Vemavarapu

@Dula: вопрос неясен относительно того, aдолжен ли он изменяться, но (как показывает Алехья) тривиально обрабатывать любой случай при использовании понимания списка.
— outis

34
Если вы хотите изменить, aто вам следует это сделать a[:] = [4 if x==1 else x for x in a](обратите внимание на полный список фрагментов). Просто сделав a =, создаст новый список aс другим id()(личность) от оригинала
— Chris_Rands

39

Понимание списков работает хорошо, и циклическое выполнение с помощью перечисления может сэкономить вам немного памяти (поскольку операция по существу выполняется на месте).

Там также функциональное программирование. Смотрите использование карты :

>>> a = [1,2,3,2,3,4,3,5,6,6,5,4,5,4,3,4,3,2,1]
>>> map(lambda x: x if x != 4 else 'sss', a)
[1, 2, 3, 2, 3, 'sss', 3, 5, 6, 6, 5, 'sss', 5, 'sss', 3, 'sss', 3, 2, 1]

17
+1. Это очень плохо lambdaи mapсчитается непитонным.
— outis

4
Я не уверен, что лямбда или карта по своей сути непифоничны, но я согласен, что понимание списка чище и более читабельно, чем использование двух из них в сочетании.
— Дамзам

7
Я сам не считаю их непифоническими, но многие это делают, включая Гвидо ван Россума ( artima.com/weblogs/viewpost.jsp?thread=98196 ). Это одна из тех сектантских вещей.
— 2010 г.

36

Если вам нужно заменить несколько значений, вы также можете использовать словарь:

a = [1, 2, 3, 4, 1, 5, 3, 2, 6, 1, 1]
dic = {1:10, 2:20, 3:'foo'}

print([dic.get(n, n) for n in a])

> [10, 20, 'foo', 4, 10, 5, 'foo', 20, 6, 10, 10]

1
Разве это не выдает ошибку, если nне найден в dic?
— Нил А.

3
@ user2914540 Я немного улучшил ваш ответ, чтобы он работал, если nне найден. Надеюсь, ты не против. Ваше try/exceptрешение не было хорошим.
— jrjc

Ах да, так лучше.
— roipoussiere

1
@jrjc @roipoussiere для замены на месте, как try-exceptминимум на 50% быстрее! Взгляните на этот ответ
— lifebalance

4
if n in dic.keys()плохая производительность. Использовать if n in dicили dic.get(n,n)(значение по умолчанию)
— Жан-Франсуа Фабр

12
>>> a=[1,2,3,4,5,1,2,3,4,5,1]
>>> item_to_replace = 1
>>> replacement_value = 6
>>> indices_to_replace = [i for i,x in enumerate(a) if x==item_to_replace]
>>> indices_to_replace
[0, 5, 10]
>>> for i in indices_to_replace:
...     a[i] = replacement_value
... 
>>> a
[6, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6]
>>> 

Средне быстрый, но очень разумный метод. Пожалуйста, посмотрите сроки в моем ответе.
— Дауг

10
a = [1,2,3,4,5,1,2,3,4,5,1,12]
for i in range (len(a)):
    if a[i]==2:
        a[i]=123

Вы можете использовать цикл for и or while; однако если вы знаете встроенную функцию Enumerate, то рекомендуется использовать Enumerate. 1


1
Это единственный разумный (читабельный) способ сделать это, когда вам нужно выполнить более сложные операции с элементами списка. Например, если каждый элемент списка представляет собой длинную строку, требующую какого-либо поиска и замены.
— not2qubit

8

Чтобы легко заменить все 1с 10в a = [1,2,3,4,5,1,2,3,4,5,1]один можно использовать следующий однострочный комбинацию лямбда + карты, и "Смотри, мама, нет IfS или Форс! :

# This substitutes all '1' with '10' in list 'a' and places result in list 'c':

c = list(map(lambda b: b.replace("1","10"), a))


Самый медленный метод на сегодняшний день. Вы вызываете lambdaкаждый элемент списка ...
— Дауг

4

Ниже приведен очень прямой метод в Python 2.x

 a = [1,2,3,4,5,1,2,3,4,5,1]        #Replacing every 1 with 10
 for i in xrange(len(a)):
   if a[i] == 1:
     a[i] = 10  
 print a

Этот метод работает. Комментарии приветствуются. Надеюсь, поможет :)

Также попытайтесь понять, как работают решения outis и damzam . Сжатия списков и лямбда-функции являются полезными инструментами.


4

В длинных списках и редких случаях использование примерно в 3 раза быстрее list.index()- по сравнению с одношаговыми итерационными методами, представленными в других ответах.

def list_replace(lst, old=1, new=10):
    """replace list elements (inplace)"""
    i = -1
    try:
        while 1:
            i = lst.index(old, i + 1)
            lst[i] = new
    except ValueError:
        pass

Это самый быстрый метод, который я нашел. Пожалуйста, посмотрите сроки в моем ответе. Большой!
— Дауг

3

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

import numpy

arr = numpy.asarray([1, 6, 1, 9, 8])
arr[ arr == 8 ] = 0 # change all occurrences of 8 by 0
print(arr)

3

Мой вариант использования был заменен Noneнекоторым значением по умолчанию.

Я рассчитал подходы к этой проблеме, которые были представлены здесь, в том числе @kxr - using str.count.

Тестовый код в ipython с Python 3.8.1:

def rep1(lst, replacer = 0):
    ''' List comprehension, new list '''

    return [item if item is not None else replacer for item in lst]


def rep2(lst, replacer = 0):
    ''' List comprehension, in-place '''    
    lst[:] =  [item if item is not None else replacer for item in lst]

    return lst


def rep3(lst, replacer = 0):
    ''' enumerate() with comparison - in-place '''
    for idx, item in enumerate(lst):
        if item is None:
            lst[idx] = replacer

    return lst


def rep4(lst, replacer = 0):
    ''' Using str.index + Exception, in-place '''

    idx = -1
    # none_amount = lst.count(None)
    while True:
        try:
            idx = lst.index(None, idx+1)
        except ValueError:
            break
        else:
            lst[idx] = replacer

    return lst


def rep5(lst, replacer = 0):
    ''' Using str.index + str.count, in-place '''

    idx = -1
    for _ in range(lst.count(None)):
        idx = lst.index(None, idx+1)
        lst[idx] = replacer

    return lst


def rep6(lst, replacer = 0):
    ''' Using map, return map iterator '''

    return map(lambda item: item if item is not None else replacer, lst)


def rep7(lst, replacer = 0):
    ''' Using map, return new list '''

    return list(map(lambda item: item if item is not None else replacer, lst))


lst = [5]*10**6
# lst = [None]*10**6

%timeit rep1(lst)    
%timeit rep2(lst)    
%timeit rep3(lst)    
%timeit rep4(lst)    
%timeit rep5(lst)    
%timeit rep6(lst)    
%timeit rep7(lst)    

Я получил:

26.3 ms ± 163 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
29.3 ms ± 206 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
33.8 ms ± 191 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
11.9 ms ± 37.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
11.9 ms ± 60.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
260 ns ± 1.84 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
56.5 ms ± 204 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Использование внутреннего str.indexна самом деле быстрее, чем любое ручное сравнение.

Я не знал, будет ли исключение в тесте 4 более трудоемким, чем использование str.count , разница кажется незначительной.

Обратите внимание, что map()(тест 6) возвращает итератор, а не фактический список, таким образом, тест 7.


2

Вы можете просто использовать понимание списка в python:

def replace_element(YOUR_LIST, set_to=NEW_VALUE):
    return [i
            if SOME_CONDITION
            else NEW_VALUE
            for i in YOUR_LIST]

для вашего случая, когда вы хотите заменить все вхождения 1 на 10, фрагмент кода будет выглядеть так:

def replace_element(YOUR_LIST, set_to=10):
    return [i
            if i != 1  # keeps all elements not equal to one
            else set_to  # replaces 1 with 10
            for i in YOUR_LIST]

3
Хотя этот фрагмент кода может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код. Также постарайтесь не переполнять ваш код пояснительными комментариями, это снижает удобочитаемость кода и пояснений!
— Филнор

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.