tìm kiếm và thay thế các yếu tố trong một danh sách


273

Tôi phải tìm kiếm thông qua một danh sách và thay thế tất cả các lần xuất hiện của một yếu tố này bằng một yếu tố khác. Cho đến nay những nỗ lực của tôi trong mã đang không đưa tôi đến đâu, cách tốt nhất để làm điều này là gì?

Ví dụ: giả sử danh sách của tôi có các số nguyên sau

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

và tôi cần thay thế tất cả các lần xuất hiện của số 1 bằng giá trị 10 để đầu ra tôi cần là

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

Do đó, mục tiêu của tôi là thay thế tất cả các trường hợp của số 1 bằng số 10.


11
Nhân tiện, cái này để làm gì?
outis

Câu trả lời:


249
>>> 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
Đây là một giải pháp xấu và rất không pythonic. Xem xét sử dụng danh sách hiểu.
AdHominem

201
Đây là một tiền phạt nếu giải pháp rất không pythonic. Xem xét sử dụng danh sách hiểu.
Jean-François Corbett

Cân nhắc sử dụng khả năng hiểu danh sách, chẳng hạn như được thực hiện bởi @outis bên dưới!
amc

6
Điều này thực hiện tốt hơn so với hiểu danh sách mặc dù không? Nó thực hiện cập nhật tại chỗ thay vì tạo một danh sách mới.
neverendingqs

@neverendingqs: Không. Thông dịch viên chi phối hoạt động, và sự hiểu biết có ít hơn về nó. Việc hiểu thực hiện tốt hơn một chút, đặc biệt là với tỷ lệ cao hơn các yếu tố vượt qua điều kiện thay thế. Có một số thời gian: ideone.com/ZrCy6z
user2357112 hỗ trợ Monica

516

Hãy thử sử dụng một sự hiểu biết danh sáchtoán tử 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
Nhưng điều này không thay đổi amặc dù phải không? Tôi nghĩ OP muốn athay đổi
Dula

10
@Dula bạn có thể thực hiện a = [4 nếu x == 1 người khác x cho x trong a], điều này sẽ có hiệu lực a
Alekhya Vemavarapu

@Dula: câu hỏi mơ hồ là liệu có anên đột biến hay không, nhưng (như Alekhya chỉ ra) việc xử lý một trong hai trường hợp khi sử dụng một cách hiểu danh sách là chuyện nhỏ.
outis

34
Nếu bạn muốn đột biến athì bạn nên làm a[:] = [4 if x==1 else x for x in a](lưu ý lát danh sách đầy đủ). Chỉ cần thực hiện a =sẽ tạo ra một danh sách mới avới một id()(danh tính) khác với danh sách ban đầu
Chris_Rands

39

Khả năng hiểu danh sách hoạt động tốt và việc lặp lại với phép liệt kê có thể giúp bạn tiết kiệm một số bộ nhớ (b / c về cơ bản hoạt động được thực hiện tại chỗ).

Ngoài ra còn có chức năng lập trình. Xem cách sử dụng bả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. Nó quá tệ lambdamapđược coi là unpythonic.
outis

4
Tôi không chắc chắn rằng lambda hoặc bản đồ vốn đã không phổ biến, nhưng tôi đồng ý rằng việc hiểu danh sách sẽ sạch hơn và dễ đọc hơn so với việc sử dụng kết hợp cả hai.
damzam

7
Bản thân tôi không coi chúng là unpythonic, nhưng nhiều người cũng vậy, kể cả Guido van Rossum ( artima.com/weblogs/viewpost.jsp?thread=98196 ). Đó là một trong những điều giáo phái.
outis

35

Nếu bạn có một vài giá trị để thay thế, bạn cũng có thể sử dụng từ điển:

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
Điều này có gây ra lỗi không nếu nkhông tìm thấy dic?
Neil A.

3
@ user2914540 Tôi đã cải thiện câu trả lời của bạn một chút để nó hoạt động nếu nkhông tìm thấy. Tôi hy vọng bạn không phiền. try/exceptGiải pháp của bạn không tốt.
jrjc

Ồ vâng, điều đó tốt hơn.
roipoussiere

1
@jrjc @roipoussiere để thay thế tại chỗ, try-exceptnhanh hơn ít nhất 50%! Hãy xem câu trả lời
tuổi thọ

4
if n in dic.keys()là hiệu suất kém khôn ngoan. Sử dụng if n in dichoặc dic.get(n,n)(giá trị mặc định)
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]
>>> 

Phương pháp trung bình nhanh nhưng rất hợp lý. Xin vui lòng xem thời gian trong câu trả lời của tôi.
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

Bạn có thể sử dụng một vòng lặp for và hoặc while; tuy nhiên nếu bạn biết hàm Enum Cả tích hợp, thì nên sử dụng Enum Cả. 1


1
Đây là cách duy nhất (có thể đọc được) để làm điều đó khi bạn cần thực hiện các thao tác phức tạp hơn trên các mục danh sách. Ví dụ: nếu mỗi mục danh sách là một chuỗi dài cần một số loại tìm kiếm và thay thế.
not2qubit

8

Để thay thế một cách dễ dàng tất cả 1với 10trong a = [1,2,3,4,5,1,2,3,4,5,1]người ta có thể sử dụng một dòng lambda + bản đồ kết hợp sau đây, và 'Look, Ma, không IFs hoặc 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))


Phương pháp chậm nhất cho đến nay. Bạn đang gọi một lambdaphần tử trong danh sách ...
dawg

4

Sau đây là một phương thức rất trực tiếp trong 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

Phương pháp này hoạt động. Bình luận được chào đón. Hy vọng nó giúp :)

Cũng cố gắng tìm hiểu cách của outisdamzam của các giải pháp làm việc. Danh sách nén và chức năng lambda là các công cụ hữu ích.


3

Tôi biết đây là một câu hỏi rất cũ và có vô số cách để làm điều đó. Đơn giản hơn tôi tìm thấy là sử dụng numpygói.

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 của tôi đã thay thế Nonebằng một số giá trị mặc định.

Tôi đã định thời các cách tiếp cận cho vấn đề này đã được trình bày ở đây, bao gồm cả phương pháp của @kxr - sử dụng str.count.

Kiểm tra mã trong ipython với 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)    

Tôi có:

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)

Sử dụng nội bộ str.indextrên thực tế nhanh hơn bất kỳ so sánh thủ công.

Tôi không biết nếu ngoại lệ trong thử nghiệm 4 sẽ tốn nhiều công sức hơn so với sử dụng str.count, sự khác biệt có vẻ không đáng kể.

Lưu ý rằng map()(kiểm tra 6) trả về một trình vòng lặp chứ không phải danh sách thực tế, do đó kiểm tra 7.


3

Trên các danh sách dài và các lần xuất hiện hiếm, nó sử dụng nhanh hơn khoảng 3 lần list.index()- so với các phương pháp lặp một bước được trình bày trong các câu trả lời khác.

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

Đây là phương pháp nhanh nhất tôi đã tìm thấy. Xin vui lòng xem thời gian trong câu trả lời của tôi. Tuyệt quá!
dawg

2

Bạn chỉ có thể sử dụng hiểu danh sách trong python:

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

đối với trường hợp của bạn, nơi bạn muốn thay thế tất cả các lần xuất hiện của 1 bằng 10, đoạn mã sẽ như thế này:

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
Mặc dù đoạn mã này có thể giải quyết câu hỏi, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn. Xin vui lòng cố gắng không làm đông mã của bạn với các bình luận giải thích, điều này làm giảm khả năng đọc của cả mã và các giải thích!
Filnor

-1

Tìm và thay thế chỉ một mục

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]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.