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.

James
sumber
11
Ngomong-ngomong, untuk apa ini?
outis
Gandakan stackoverflow.com/q/1540049/819417
Cees Timmerman

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]
ghostdog74
sumber
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]
outis
sumber
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]
damzam
sumber
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]
roipoussiere
sumber
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]
>>> 
John La Rooy
sumber
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

Eimal Dorani
sumber
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))

J. Paul
sumber
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.

Ananay Mital
sumber
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
kxr
sumber
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)
Tiago Vieira
sumber
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.

Jay
sumber
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]
bassel7
sumber
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]
bereket gebredingle
sumber