menemukan dan mengganti elemen dalam daftar


273

Saya harus mencari melalui daftar dan mengganti semua kemunculan satu elemen dengan elemen lainnya. Sejauh ini upaya saya dalam mendapatkan kode saya tidak ada, apa cara terbaik untuk melakukan ini?

Sebagai contoh, misalkan daftar saya memiliki bilangan bulat berikut

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

dan saya harus mengganti semua kemunculan angka 1 dengan nilai 10 sehingga output yang saya butuhkan adalah

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

Jadi tujuan saya adalah mengganti semua instance dari angka 1 dengan angka 10.


11
Ngomong-ngomong, untuk apa ini?
outis

Jawaban:


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
Ini adalah solusi yang buruk dan sangat tidak pythonic. Pertimbangkan untuk menggunakan pemahaman daftar.
AdHominem

205
Ini adalah solusi yang baik jika sangat tidak pythonic. Pertimbangkan untuk menggunakan pemahaman daftar.
Jean-François Corbett

Pertimbangkan untuk menggunakan pemahaman daftar, seperti yang dilakukan oleh @outis di bawah ini!
amc

6
Ini berkinerja lebih baik daripada pemahaman daftar, bukan? Itu pembaruan di tempat bukannya menghasilkan daftar baru.
neverendingqs

@neverendingqs: Tidak. Overpreter overhead mendominasi operasi, dan pemahamannya lebih sedikit. Pemahaman berkinerja sedikit lebih baik, terutama dengan proporsi elemen yang lebih tinggi melewati kondisi penggantian. Memiliki beberapa timing: ideone.com/ZrCy6z
user2357112 mendukung Monica

519

Coba gunakan pemahaman daftar dan operator ternary .

>>> 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
Tapi ini tidak berubah akan? Saya pikir OP ingin aberubah
Dula

10
@Dula Anda dapat melakukan = [4 jika x == 1 x untuk x dalam a], ini akan berpengaruh
Alekhya Vemavarapu

@ Dula: pertanyaannya tidak jelas apakah aharus bermutasi, tetapi (seperti yang ditunjukkan oleh Alekhya) itu sepele untuk menangani kedua kasus ketika menggunakan daftar pemahaman.
outis

34
Jika Anda ingin bermutasi amaka Anda harus melakukannya a[:] = [4 if x==1 else x for x in a](perhatikan daftar lengkap slice). Hanya melakukan a =kehendak akan membuat daftar baru adengan id()(identitas) yang berbeda dari yang asli
Chris_Rands

39

Pemahaman daftar berfungsi dengan baik, dan mengulang dengan penghitungan dapat menghemat memori Anda (b / c operasi pada dasarnya dilakukan di tempat).

Ada juga pemrograman fungsional. Lihat penggunaan peta :

>>> 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. Terlalu buruk lambdadan mapdianggap unpythonic.
outis

4
Saya tidak yakin lambda atau peta itu inheren unpythonic, tapi saya setuju bahwa pemahaman daftar lebih bersih dan lebih mudah dibaca daripada menggunakan keduanya bersamaan.
damzam

7
Saya sendiri tidak menganggapnya unpythonic, tetapi banyak yang melakukannya, termasuk Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ). Itu salah satu hal sektarian itu.
outis

36

Jika Anda memiliki beberapa nilai untuk diganti, Anda juga dapat menggunakan kamus:

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
Tidakkah ini menghasilkan kesalahan jika ntidak ditemukan dic?
Neil A.

3
@ user2914540 Saya sedikit memperbaiki jawaban Anda sehingga berfungsi jika ntidak ditemukan. Saya harap kamu tidak keberatan. try/exceptSolusi Anda tidak bagus.
jrjc

Oh ya, itu lebih baik.
roipoussiere

1
@jrjc @roipoussiere untuk penggantian di tempat, try-exceptsetidaknya 50% lebih cepat! Lihatlah jawaban
seumur hidup

4
if n in dic.keys()adalah kinerja yang buruk. Gunakan if n in dicatau dic.get(n,n)(nilai default)
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]
>>> 

Metode cepat sedang tetapi sangat masuk akal. Silakan lihat timing dalam jawaban saya.
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

Anda dapat menggunakan loop for dan atau while; namun jika Anda mengetahui fungsi Enumerate bawaan, maka disarankan untuk menggunakan Enumerate. 1


1
Ini adalah satu-satunya cara yang waras (dapat dibaca) untuk melakukannya ketika Anda perlu melakukan operasi yang lebih kompleks pada daftar item. Misalnya, jika setiap item daftar adalah string panjang yang memerlukan semacam pencarian dan penggantian.
not2qubit

8

Untuk mengganti semua 1dengan dengan mudah 10dalam a = [1,2,3,4,5,1,2,3,4,5,1]satu dapat menggunakan kombinasi peta lambda + satu baris berikut, dan 'Lihat, Bu, tidak ada IF atau FORs!' :

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


Metode paling lambat sejauh ini. Anda menelepon lambdapada setiap elemen daftar ...
dawg

4

Berikut ini adalah metode yang sangat langsung di 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

Metode ini berhasil. Komentar diterima. Semoga bermanfaat :)

Juga mencoba memahami bagaimana outis ini dan damzam ini solusi kerja. Daftar kompresi dan fungsi lambda adalah alat yang berguna.


4

Pada daftar panjang dan kejadian langka sekitar 3x lebih cepat menggunakan list.index()- dibandingkan dengan metode iterasi satu langkah yang disajikan dalam jawaban lain.

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

Ini adalah metode tercepat yang saya temukan. Silakan lihat timing dalam jawaban saya. Bagus!
dawg

3

Saya tahu ini adalah pertanyaan yang sangat lama dan ada banyak cara untuk melakukannya. Yang lebih sederhana yang saya temukan adalah menggunakan numpypaket.

import numpy

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

3

Usecase saya diganti Nonedengan beberapa nilai default.

Saya telah menghitung waktu pendekatan untuk masalah ini yang disajikan di sini, termasuk yang oleh @kxr - using str.count.

Uji kode dalam ipython dengan 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)    

Saya mendapat:

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)

Menggunakan internal str.indexsebenarnya lebih cepat daripada perbandingan manual.

Saya tidak tahu apakah pengecualian dalam tes 4 akan lebih sulit daripada menggunakan str.count , perbedaannya tampaknya dapat diabaikan.

Perhatikan bahwa map()(tes 6) mengembalikan iterator dan bukan daftar yang sebenarnya, dengan demikian tes 7.


2

Anda bisa menggunakan daftar pemahaman dalam python:

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

untuk kasus Anda, di mana Anda ingin mengganti semua kejadian 1 dengan 10, cuplikan kode akan seperti ini:

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
Sementara potongan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda. Tolong juga cobalah untuk tidak membuat kerumunan kode Anda dengan komentar penjelasan, ini mengurangi keterbacaan kode dan penjelasan!
Filnor

-1

Temukan & ganti hanya satu item

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]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.