знаходження та заміна елементів у списку


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
Для чого це, до речі?
outis

Відповіді:


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

203
Це штраф, якщо дуже непітонічне рішення. Подумайте про використання списків.
Жан-Франсуа Корбетт

Подумайте про використання списку розуміння, як це зроблено @outis нижче!
amc

6
Це краще, ніж розуміння списку, хоча це не так? Здійснює оновлення на місці замість створення нового списку.
neverendingqs

@neverendingqs: Ні. Накладні перекладачі домінують над операцією, і розуміння має її менше. Розуміння працює трохи краще, особливо з більшою часткою елементів, що передають умову заміни. У вас є деякі терміни: ideone.com/ZrCy6z
user2357112 підтримує Моніка

517

Спробуйте використати розуміння списку та термінального оператора .

>>> 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хоча правда? Я думаю, що ОП хотів aзмінитись
Дула

10
@Dula, ви можете зробити a = [4, якщо x == 1 else x for x in 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 ). Це одна з тих сектантських речей.
outis

35

Якщо у вас є кілька значень для заміни, ви також можете використовувати словник:

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% швидше! Подивіться на цю відповідь
життєвий баланс

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]
>>> 

Середньо швидкий, але дуже розумний метод. Будь ласка, дивіться терміни моєї відповіді.
dawg

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

Ви можете використовувати цикл для і або під час; однак якщо ви знаєте функцію вбудованого перерахування, рекомендується використовувати 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на кожен елемент списку ...
dawg

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

Цей метод працює. Коментарі вітаються. Сподіваюся, це допомагає :)

Спробуйте також зрозуміти, як працюють рішення сторонніх та дамзам . Перелік стиснення та лямбда-функції - корисні інструменти.


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 - використовуючи 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.


3

У довгих списках та рідкісних явищах його використання приблизно в 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

Це найшвидший метод, який я знайшов. Будь ласка, дивіться терміни моєї відповіді. Чудово!
dawg

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
Хоча цей фрагмент коду може вирішити питання, у тому числі пояснення дійсно допомагає покращити якість вашої публікації. Пам'ятайте, що ви відповідаєте на запитання читачів у майбутньому, і ці люди можуть не знати причини вашої пропозиції щодо коду. Будь ласка, намагайтеся не переповнювати свій код пояснювальними коментарями, це зменшує читабельність і коду, і пояснень!
Фільнор

-1

Знайдіть і замініть лише один предмет

ur_list = [1,2,1]     # replace the first 1 wiz 11

loc = ur_list.index(1)
ur_list.remove(1)
ur_list.insert(loc, 11)

----------
[11,2,1]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.