listedeki öğeleri bulma ve değiştirme


273

Bir liste aramak ve bir elemanın tüm tekrarlarını başka bir elemanla değiştirmek zorundayım. Şimdiye kadar kod girişimlerim beni hiçbir yere götürmüyor, bunu yapmanın en iyi yolu nedir?

Örneğin, listemde aşağıdaki tamsayıların olduğunu varsayalım

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

ve 1 numarasının tüm tekrarlarını 10 değeriyle değiştirmem gerekiyor, böylece ihtiyacım olan çıktı

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

Bu yüzden amacım 1 numarasının tüm örneklerini 10 rakamıyla değiştirmek.


11
Bu arada bu ne için?
outis

Yanıtlar:


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
Bu kötü ve pythonic olmayan bir çözümdür. Liste kavrayışı kullanmayı düşünün.
AdHominem

203
Bu çok pythonic olmayan bir çözümdür. Liste kavrayışı kullanmayı düşünün.
Jean-François Corbett

Aşağıdaki @outis gibi bir liste kavrayışı kullanmayı düşünün!
amc

6
Bu, liste kavrayışından daha iyi performans göstermesine rağmen, öyle değil mi? Yeni bir liste oluşturmak yerine yerinde güncellemeler yapar.
neverendingqs

@neverendingqs: Hayır. Tercüman yükü operasyona hâkimdir ve kavrayışın daha azı vardır. Anlama biraz daha iyi performans gösterir, özellikle de değiştirme koşulundan geçen elemanların daha yüksek bir oranıyla. Bazı zamanlamalarınız var: ideone.com/ZrCy6z
user2357112 Monica

519

Bir liste kavrayışı ve üçlü operatör kullanmayı deneyin .

>>> 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
Ama bu değişmiyor değil ami? Sanırım OP adeğiştirmek istedi
Dula

10
@Dula, a = [x == 1 x için x başka x varsa], bu
a'yı etkiler

@Dula: Soru amutasyona uğraması gerekip gerekmediği konusunda belirsiz , ancak (Alekhya'nın gösterdiği gibi) bir liste kavrayışı kullanırken her iki durumu da ele almak önemsizdir.
outis

34
Eğer mutasyona uğramak aistiyorsanız, yapmalısınız a[:] = [4 if x==1 else x for x in a](tam liste dilimini not edin). Sadece yapmak orijinalinden farklı (kimlik) a =yeni bir liste oluşturacakaid()
Chris_Rands

39

Liste anlama iyi çalışır ve numaralandırma ile döngü yapmak size biraz hafıza kazandırabilir (b / c işlemin esasen yerinde yapıldığını).

Ayrıca fonksiyonel programlama da var. Haritanın kullanımına bakın :

>>> 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. Çok kötü lambdave mapunpythonic olarak kabul edilir.
outis

4
Lambda veya haritanın doğası gereği tek sesli olmadığı konusunda emin değilim, ancak bir liste kavrayışının ikisini birlikte kullanmaktan daha temiz ve daha okunabilir olduğuna katılıyorum.
damzam

7
Onları kendim sessiz olarak görmüyorum, ancak Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ) dahil olmak üzere birçok kişi bunu düşünüyor . O mezhepsel şeylerden biri.
outis

36

Değiştirilecek birkaç değeriniz varsa, bir sözlük de kullanabilirsiniz:

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
Eğer bu bir hata atmak gelmez nbulunmaz dic?
Neil A.

3
@ user2914540 Cevabınızı biraz geliştirdim, böylece nbulunmazsa çalışır . Umarım umursamazsın. Sizin try/exceptçözüm iyi değildi.
jrjc

Ah evet, bu daha iyi.
roipoussiere

1
Yerinde değiştirme için @jrjc @roipoussiere try-except, en az% 50 daha hızlı! Bu cevaba
lifebalance

4
if n in dic.keys()performans açısından kötüdür. Kullanın if n in dicveya dic.get(n,n)(varsayılan değer)
Jean-François Fabre

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

Orta hızlı ama çok mantıklı bir yöntem. Lütfen cevabımdaki zamanlamaları görün.
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

For ve veya while döngüsü kullanabilirsiniz; Ancak u yerleşik Enumerate işlevini biliyorsanız, Enumerate kullanılması önerilir. 1


1
Bu, liste öğelerinde daha karmaşık işlemler yapmanız gerektiğinde bunu yapmanın tek aklı başında (okunabilir) yoludur. Örneğin, her liste öğesi bir tür arama ve değiştirme gerektiren uzun bir dize ise.
not2qubit

8

Tüm kolayca değiştirmek için 1birlikte 10de a = [1,2,3,4,5,1,2,3,4,5,1]'Bak anne, hiçbir UF'ların veya Fors!' Tek aşağıdaki tek satırlık lambda + harita birleşimini kullanabilir ve :

# 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))


Şimdiye kadar en yavaş yöntem. Bir aradığınız lambda... Her liste elemanı üzerinde
dawg

4

Aşağıdaki Python 2.x çok doğrudan bir yöntemdir

 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

Bu yöntem işe yarar. Yorumlarınızı bekliyoruz. Umarım yardımcı olur :)

Ayrıca nasıl anlamak deneyin outis en ve damzam en çözümleri çalışır. Liste sıkıştırma ve lambda fonksiyonu kullanışlı araçlardır.


4

Uzun listelerde ve nadir durumlarda list.index(), diğer cevaplarda sunulan tek aşamalı yineleme yöntemlerine kıyasla yaklaşık 3 kat daha hızlıdır .

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

Bu bulduğum en hızlı yöntem. Lütfen cevabımdaki zamanlamaları görün. Harika!
dawg

3

Bunun çok eski bir soru olduğunu biliyorum ve bunu yapmanın sayısız yolu var. Bulduğum daha basit olanı numpypaket kullanmak .

import numpy

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

3

Kullanıcı tabanım Nonebazı varsayılan değerlerle değiştiriliyordu .

@Kxr - kullanarak da dahil olmak üzere burada sunulan bu probleme zamanlanmış yaklaşımlar kullanıyorum str.count.

Python 3.8.1 ile ipython'daki test kodu:

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)    

Alırım:

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)

Dahili str.indexkullanımı aslında herhangi bir manuel karşılaştırmadan daha hızlıdır.

Test 4'teki istisnanın kullanmaktan daha zahmetli olup olmadığını bilmiyordum str.count, fark göz ardı edilebilir görünüyor.

map()(Test 6) 'nın gerçek bir liste değil bir yineleyici döndürdüğünü unutmayın , böylece test 7.


2

Basitçe python'da liste kavrama özelliğini kullanabilirsiniz:

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

1'in tüm tekrarlarını 10 ile değiştirmek istediğiniz durumunuz için, kod snippet'i aşağıdaki gibi olacaktır:

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
Bu kod snippet'i soruyu çözebilir, ancak bir açıklama da dahil olmak , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın. Lütfen kodunuzu açıklayıcı yorumlarla doldurmamaya çalışın, bu hem kodun hem de açıklamaların okunabilirliğini azaltır!
Filnor

-1

Yalnızca bir öğeyi bulma ve değiştirme

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]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.