การค้นหาและแทนที่องค์ประกอบในรายการ


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
นี่เป็นวิธีแก้ปัญหาที่ดีมาก พิจารณาการใช้รายการความเข้าใจ
Jean-François Corbett

พิจารณาการใช้รายการความเข้าใจเช่นทำโดย @outis ด้านล่าง!
amc

6
สิ่งนี้ทำงานได้ดีกว่าความเข้าใจในรายการ แต่ไม่ใช่หรือไม่ มันทำหน้าที่อัปเดตแทนการสร้างรายการใหม่
neverendingqs

@neverendingqs: ไม่ค่าใช้จ่ายของล่ามจะควบคุมการดำเนินการและความเข้าใจมีน้อย ความเข้าใจมีประสิทธิภาพดีขึ้นเล็กน้อยโดยเฉพาะอย่างยิ่งเมื่อสัดส่วนที่สูงขึ้นขององค์ประกอบผ่านเงื่อนไขการทดแทน มีการกำหนดเวลาบางอย่าง: ideone.com/ZrCy6z
user2357112 รองรับ Monica

517

ลองใช้list comprehensionและoperator ที่ประกอบไปด้วย

>>> 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ใช่มั้ย ฉันคิดว่า OP ต้องการaเปลี่ยนแปลง
Dula

10
@Dula คุณสามารถทำ = [4 ถ้า x == 1 อื่น x สำหรับ x ใน a] นี้จะมีผล
Alekhya Vemavarapu

@Dula: คำถามที่คลุมเครือว่าaควรจะกลายพันธุ์ แต่ (ตามที่ Alekhya แสดงให้เห็น) มันเป็นเรื่องเล็กน้อยที่จะจัดการกับกรณีใดกรณีหนึ่งเมื่อใช้รายการความเข้าใจ
outis

34
ถ้าคุณต้องการที่จะกลายพันธุ์aคุณควรทำa[:] = [4 if x==1 else x for x in a](จดรายการชิ้นเต็ม) เพิ่งจะทำa =จะสร้างรายการใหม่ที่aมีid()(ตัวตน) ที่แตกต่างจากรายการเดิม
Chris_Rands

39

รายการความเข้าใจใช้งานได้ดีและการวนซ้ำด้วยการแจกแจงสามารถช่วยให้คุณประหยัดหน่วยความจำได้บ้าง (b / c การดำเนินการของสถานที่นั้นเป็นหลัก)

นอกจากนี้ยังมีการเขียนโปรแกรมใช้งานได้ ดูการใช้งานแผนที่ :

>>> 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
ฉันไม่แน่ใจว่าแลมบ์ดาหรือแผนที่ไม่ได้เน้นเสียงโดยเนื้อแท้ แต่ฉันเห็นด้วยว่าความเข้าใจในรายการนั้นสะอาดและอ่านง่ายกว่าการใช้ทั้งสองอย่างร่วมกัน
damzam

7
ฉันไม่คิดว่าพวกเขาจะไม่เน้นเสียงตัวเอง แต่หลายคนรวมถึง Guido van Rossum ( 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หรือไม่
Neil A.

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)(ค่าเริ่มต้น)
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]
>>> 

วิธีการเร็วปานกลาง แต่มีเหตุผลมาก โปรดดูเวลาในคำตอบของฉัน
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

คุณสามารถใช้สำหรับและหรือในขณะที่วง; อย่างไรก็ตามถ้าหากคุณรู้ว่าฟังก์ชั่นแจกแจงแล้วแนะนำให้ใช้การแจกแจง 1


1
นี่เป็นวิธีเดียวที่มีเหตุผล (อ่านได้) ที่จะทำเมื่อคุณต้องการดำเนินการที่ซับซ้อนมากขึ้นในรายการ ตัวอย่างเช่นหากรายการแต่ละรายการเป็นสตริงยาวที่ต้องการการค้นหาและแทนที่
not2qubit

8

หากต้องการแทนที่ทั้งหมดอย่างง่ายดาย1ด้วย10in a = [1,2,3,4,5,1,2,3,4,5,1]one สามารถใช้ชุดแลมบ์ดา + แผนที่แบบบรรทัดเดียวต่อไปนี้และ 'Look, Ma, no IFs or 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))


วิธีที่ช้าที่สุดโดยไกล คุณกำลังเรียก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

วิธีนี้ใช้ได้ผล ความคิดเห็นยินดีต้อนรับ หวังว่าจะช่วย :)

นอกจากนี้ยังพยายามทำความเข้าใจวิธีการของ outisและdamzam ของการแก้ปัญหาการทำงาน รายการการบีบอัดและฟังก์ชั่นแลมบ์ดาเป็นเครื่องมือที่มีประโยชน์


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

usecase ของฉันถูกแทนที่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

ในรายการที่มีขนาดยาวและเกิดขึ้นได้ยากกว่านั้นใช้ประมาณ 3x เร็วกว่า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

คุณสามารถใช้ list comprehension ใน 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
ในขณะที่ข้อมูลโค้ดนี้อาจแก้ไขคำถามรวมถึงคำอธิบายช่วยปรับปรุงคุณภาพของโพสต์ของคุณ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและคนเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำรหัสของคุณ โปรดอย่าพยายามทำให้รหัสของคุณแน่นเกินไปด้วยคำอธิบายที่อธิบายซึ่งจะช่วยลดความสามารถในการอ่านของทั้งรหัสและคำอธิบาย!
Filnor

-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]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.