ลบค่าทั้งหมดที่เกิดขึ้นจากรายการหรือไม่


377

ใน Python remove()จะลบค่าที่เกิดขึ้นครั้งแรกในรายการ

วิธีการลบค่าที่เกิดขึ้นทั้งหมดออกจากรายการ?

นี่คือสิ่งที่ฉันมีอยู่ในใจ:

>>> remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
[1, 3, 4, 3]

คำตอบ:


505

วิธีการทำงาน:

Python 3.x

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter((2).__ne__, x))
[1, 3, 3, 4]

หรือ

>>> x = [1,2,3,2,2,2,3,4]
>>> list(filter(lambda a: a != 2, x))
[1, 3, 3, 4]

Python 2.x

>>> x = [1,2,3,2,2,2,3,4]
>>> filter(lambda a: a != 2, x)
[1, 3, 3, 4]

120
ใช้รายการความเข้าใจเหนือตัวกรอง + แลมบ์ดา อดีตนั้นอ่านได้ง่ายและมีประสิทธิภาพมากกว่า
habnabit

17
s / โดยทั่วไป / โดยทั่วไปจะเป็น /
habnabit

99
รหัสสำหรับคำแนะนำของ habnabit มีลักษณะเช่นนี้:[y for y in x if y != 2]
coredumperror

8
ฉันจะไม่เรียกโซลูชันนี้ว่าดีที่สุด ความเข้าใจในรายการนั้นรวดเร็วและง่ายต่อการเข้าใจในขณะที่อ่านผ่านโค้ด นี่ค่อนข้างจะเป็นวิธี Perl มากกว่า Python
Peter Nimroot

3
-1 __ne__สำหรับการเรียกโดยตรง การเปรียบเทียบค่าสองค่าเป็นกระบวนการที่ซับซ้อนกว่าการโทร__eq__หรือ__ne__เพียงหนึ่งค่า มันอาจทำงานได้อย่างถูกต้องที่นี่เพราะคุณเพียงแค่เปรียบเทียบตัวเลข แต่ในกรณีทั่วไปที่ไม่ถูกต้องและข้อผิดพลาด
Aran-Fey

211

คุณสามารถใช้ list comprehension:

def remove_values_from_list(the_list, val):
   return [value for value in the_list if value != val]

x = [1, 2, 3, 4, 2, 2, 3]
x = remove_values_from_list(x, 2)
print x
# [1, 3, 4, 3]

7
คุณจะลบรายการโดยไม่ตรวจสอบได้อย่างไร
Alexander Ljungberg

18
สิ่งนี้ไม่ได้แก้ไขรายการดั้งเดิม แต่ส่งคืนรายการใหม่
John Y

6
@Selinap: ไม่เป็นสิ่งที่ดีที่สุดเพราะสแกนรายการเพียงครั้งเดียว ในรหัสต้นฉบับของคุณทั้งinผู้ดำเนินการและremoveวิธีการสแกนรายการทั้งหมด (จนกว่าพวกเขาจะพบการแข่งขัน) ดังนั้นคุณจะสิ้นสุดการสแกนรายการหลายครั้งด้วยวิธีนั้น
John Kugelman

4
@mhawke, @John Y: เพียงใช้ x [:] = ... แทนที่จะเป็น x = และมันจะเป็น "แบบแทนที่" แทนที่จะแค่เรียกชื่อ 'x' ใหม่ (ความเร็วจะเหมือนกันมากและเร็วกว่า x มาก . สามารถลบได้ !!!)
Alex Martelli

10
ผมลงคะแนนนี้ขึ้นเพราะหลังจาก 6 ปีของงูใหญ่ผมก็ยังไม่เข้าใจ Lambdas :)
เบนจามิน

107

คุณสามารถใช้การกำหนดชิ้นถ้าต้องแก้ไขรายการเดิมในขณะที่ยังคงใช้ความเข้าใจรายการอย่างมีประสิทธิภาพ (หรือนิพจน์ตัวสร้าง)

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> x[:] = (value for value in x if value != 2)
>>> x
[1, 3, 4, 3]

1
@Selinap: ตัวกรองไม่แก้ไขรายการ แต่จะส่งคืนรายการใหม่
EM

ความเข้าใจตัวกรองและรายการไม่ได้แก้ไขรายการ การมอบหมายชิ้นทำ และตัวอย่างดั้งเดิมทำ
A. Coady

7
ฉันชอบสิ่งนี้เพราะมันแก้ไขรายการที่ x อ้างถึง หากมีการอ้างอิงอื่น ๆ ไปยังรายการนั้นพวกเขาจะได้รับผลกระทบด้วย สิ่งนี้ตรงกันข้ามกับx = [ v for v in x if x != 2 ]ข้อเสนอที่สร้างรายการใหม่และเปลี่ยน x เพื่ออ้างถึงโดยปล่อยให้รายการเดิมไม่ถูกแตะต้อง
Hannes

40

ทำซ้ำโซลูชันของโพสต์แรกด้วยวิธีที่เป็นนามธรรมมากขึ้น:

>>> x = [1, 2, 3, 4, 2, 2, 3]
>>> while 2 in x: x.remove(2)
>>> x
[1, 3, 4, 3]

19
มันเป็น O (n * n)
Hannes

@ ฮันเนสจะไม่เป็น O (n) เนื่องจากมันผ่านลูปเพียงครั้งเดียว & ในเวลาเดียวกันก็เอาไอเทมออกไปด้วย?
penta

1
x = [1] * 10000 + [2] * 1000พิจารณา ตัวลูปจะดำเนินการ 1,000 ครั้งและ. Remove () ต้องข้ามองค์ประกอบ 10,000 ทุกครั้งที่เรียกใช้ มีกลิ่นเหมือน O (n * n) สำหรับฉัน แต่ไม่มีข้อพิสูจน์ ฉันคิดว่าข้อพิสูจน์จะสมมติว่าจำนวน 2s ในรายการนั้นเป็นสัดส่วนกับความยาวของมัน ปัจจัยสัดส่วนนั้นจะหายไปในสัญกรณ์ใหญ่ กรณีที่ดีที่สุดแม้ว่ามีเพียง 2 วินาทีในรายการเท่านั้นไม่ใช่ O (n ^ 2) เพียง O (2n) ซึ่งเป็น O (n)
Hannes

23

ดูวิธีแก้ปัญหาง่ายๆ

>>> [i for i in x if i != 2]

นี้จะกลับรายการมีองค์ประกอบทั้งหมดของxโดยไม่ต้อง2


11

คำตอบทั้งหมดข้างต้น (นอกเหนือจาก Martin Andersson's) สร้างรายการใหม่โดยไม่มีรายการที่ต้องการแทนที่จะลบรายการออกจากรายการเดิม

>>> import random, timeit
>>> a = list(range(5)) * 1000
>>> random.shuffle(a)

>>> b = a
>>> print(b is a)
True

>>> b = [x for x in b if x != 0]
>>> print(b is a)
False
>>> b.count(0)
0
>>> a.count(0)
1000

>>> b = a
>>> b = filter(lambda a: a != 2, x)
>>> print(b is a)
False

สิ่งนี้อาจมีความสำคัญหากคุณมีการอ้างอิงอื่น ๆ ไปยังรายการที่แขวนอยู่

หากต้องการแก้ไขรายการให้ใช้วิธีการนี้

>>> def removeall_inplace(x, l):
...     for _ in xrange(l.count(x)):
...         l.remove(x)
...
>>> removeall_inplace(0, b)
>>> b is a
True
>>> a.count(0)
0

เท่าที่เกี่ยวกับความเร็วผลลัพธ์บนแล็ปท็อปของฉันคือ (ทั้งหมดในรายการ 5000 ที่มี 1,000 รายการถูกลบออก)

  • รายการความเข้าใจ - ~ 400us
  • ตัวกรอง - ~ 900us
  • .remove () loop - 50ms

ดังนั้นการลบวงจะช้าลงประมาณ 100x ........ อืมอาจต้องใช้วิธีการอื่น เร็วที่สุดที่ฉันพบคือการใช้รายการความเข้าใจ แต่แล้วแทนที่เนื้อหาของรายการต้นฉบับ

>>> def removeall_replace(x, l):
....    t = [y for y in l if y != x]
....    del l[:]
....    l.extend(t)
  • removeall_replace () - 450us

ทำไมไม่เพียงมอบหมายรายการใหม่ภายใต้ที่อยู่เก่าแล้ว def remove_all(x, l): return [y for y in l if y != x]จากนั้นl = remove_all(3,l)
Dannid

@Danid นั่นเป็นวิธีที่สองในกล่องรหัสแรก มันสร้างรายการใหม่และคุณไม่ได้แก้ไขรายการเก่า การอ้างอิงอื่น ๆ ในรายการจะยังคงไม่มีการกรอง
Paul S

อ่าใช่มั้ย ฉันจมอยู่กับการกำหนดวิธีการฉันมองข้ามการมอบหมายง่ายๆที่คุณได้ทำไปแล้ว
Dannid

7

คุณสามารถทำได้

while 2 in x:   
    x.remove(2)

3
นั่นเป็นคำตอบที่ไม่ถูกต้องเนื่องจากรายการจะต้องถูกสำรวจ 2 * n ครั้งสำหรับการเกิด n 2 ครั้ง
cxxl

ไม่แนะนำให้เพิ่มหรือลบจากรายการที่คุณกำลังทำการสำรวจ การปฏิบัติที่ไม่ดี IMHO
Aman Mathur

5

ค่าใช้จ่ายในการอ่านได้ฉันคิดว่ารุ่นนี้เร็วกว่าเล็กน้อยเนื่องจากไม่ได้บังคับให้ต้องตรวจสอบรายการใหม่อีกครั้งดังนั้นการลบงานเดิมจึงต้องทำต่อไป:

x = [1, 2, 3, 4, 2, 2, 3]
def remove_values_from_list(the_list, val):
    for i in range(the_list.count(val)):
        the_list.remove(val)

remove_values_from_list(x, 2)

print(x)

สำหรับรายการที่คุณแสดงในรหัสของคุณวิธีการนี้ช้ากว่าวิธีการเข้าใจรายการประมาณ 36% (ซึ่งส่งคืนสำเนา) ตามการวัดของฉัน
djsmith

ดีที่คุณสังเกตเห็นว่า อย่างไรก็ตามเนื่องจากฉันคิดว่าอาจทำให้การตัดสินใจของคุณลดลงฉันจึงเปรียบเทียบรุ่นของฉันกับข้อเสนอแรกที่ผู้เขียนคำถามตั้งขึ้น
Martin Andersson

4

แนวทางและการกำหนดเวลาแบบ Numpy เทียบกับ list / array ที่มีองค์ประกอบ 1.000.000 รายการ:

การกำหนดเวลา:

In [10]: a.shape
Out[10]: (1000000,)

In [13]: len(lst)
Out[13]: 1000000

In [18]: %timeit a[a != 2]
100 loops, best of 3: 2.94 ms per loop

In [19]: %timeit [x for x in lst if x != 2]
10 loops, best of 3: 79.7 ms per loop

สรุป: numpy เร็วขึ้น 27 เท่า (บนสมุดบันทึกของฉัน) เปรียบเทียบกับวิธีการเข้าใจรายการ

PS ถ้าคุณต้องการแปลงรายการ Python ปกติของคุณเป็นlstarray numpy:

arr = np.array(lst)

ติดตั้ง:

import numpy as np
a = np.random.randint(0, 1000, 10**6)

In [10]: a.shape
Out[10]: (1000000,)

In [12]: lst = a.tolist()

In [13]: len(lst)
Out[13]: 1000000

ตรวจสอบ:

In [14]: a[a != 2].shape
Out[14]: (998949,)

In [15]: len([x for x in lst if x != 2])
Out[15]: 998949

4
a = [1, 2, 2, 3, 1]
to_remove = 1
a = [i for i in a if i != to_remove]
print(a)

บางทีมันอาจจะไม่ไพเราะที่สุด แต่ก็ยังง่ายที่สุดสำหรับฉันฮ่าฮ่า


3

หากต้องการลบรายการที่ซ้ำกันทั้งหมดและเก็บไว้ในรายการ:

test = [1, 1, 2, 3]

newlist = list(set(test))

print newlist

[1, 2, 3]

นี่คือฟังก์ชั่นที่ฉันใช้สำหรับ Project Euler:

def removeOccurrences(e):
  return list(set(e))

2
ฉันต้องการทำสิ่งนี้บนเวกเตอร์ที่มีค่า 250k และมันใช้งานได้อย่างมีเสน่ห์
rschwieb

1
คำตอบคือ: ใช่! และฉันก็เข้าใจอย่างถ่องแท้ว่าการมีเวกเตอร์ที่ฟังดูแล้วบ้าไปแล้วสำหรับโปรแกรมเมอร์ที่มีความสามารถ ฉันเข้าใกล้ปัญหาที่นั่นในฐานะนักคณิตศาสตร์โดยไม่ต้องกังวลกับการปรับแก้ปัญหาให้เหมาะสมและนั่นอาจนำไปสู่การแก้ปัญหาได้นานกว่าที่คิดไว้ (แม้ว่าฉันจะไม่อดทนกับการแก้ปัญหานานกว่า 5 นาที)
rschwieb

6
การดำเนินการนี้จะลบการสั่งซื้อใด ๆ ออกจากรายการ
asmeurer

4
@ JaredBurrows อาจเป็นเพราะมันไม่ได้ตอบคำถามตามที่เป็นอยู่ในปัจจุบัน แต่เป็นคำถามที่แตกต่างกันมาก
drevicko

6
-1 นี่ไม่ใช่คำตอบสำหรับคำถามของ OP มันเป็นวิธีการลบข้อมูลที่ซ้ำกันซึ่งเป็นเรื่องที่แตกต่างอย่างสิ้นเชิง
Anoyz

2

ฉันเชื่อว่านี่น่าจะเร็วกว่าวิธีอื่น ๆ ถ้าคุณไม่ใส่ใจเกี่ยวกับลำดับของรายการถ้าคุณดูแลเกี่ยวกับลำดับสุดท้ายที่เก็บดัชนีจากต้นฉบับและรีสอร์ต

category_ids.sort()
ones_last_index = category_ids.count('1')
del category_ids[0:ones_last_index]

2
ฉันเข้าใจว่าคุณกำลังไปไหน แต่รหัสนี้จะไม่ทำงานเนื่องจากคุณต้องการดัชนีเริ่มต้นและไม่ใช่แค่ 0
Shedokan

2
for i in range(a.count(' ')):
    a.remove(' ')

ฉันเชื่อง่ายกว่านี้มาก


2
โปรดแก้ไขคำตอบของคุณเพื่อปรับปรุงความชัดเจน โปรดระบุให้ชัดเจนว่ารหัสที่คุณแนะนำนั้นทำงานอย่างไรและทำไมจึงเป็นข้อเสนอแนะของคุณ โปรดจัดรูปแบบคำถามของคุณให้ถูกต้องเพื่อให้มองเห็นรหัสได้ชัดเจนจากคำตอบที่เหลือ
Ortund

2

ปล่อย

>>> x = [1, 2, 3, 4, 2, 2, 3]

ทางออกที่ง่ายและมีประสิทธิภาพตามที่ประกาศไว้แล้วก่อนหน้าคือ

>>> x[:] = [v for v in x if v != 2]
>>> x
[1, 3, 4, 3]

ความเป็นไปได้อื่นที่ควรใช้หน่วยความจำน้อยลง

>>> for i in range(len(x) - 1, -1, -1):
        if x[i] == 2:
            x.pop(i)  # takes time ~ len(x) - i
>>> x
[1, 3, 4, 3]

ผลการกำหนดเวลาสำหรับรายการที่มีความยาว 1,000 และ 100000 พร้อมการจับคู่ 10% รายการ: 0.16 vs 0.25 ms และ 23 vs 123 ms

เวลาที่มีความยาว 1,000

จับเวลาด้วยความยาว 100,000


1

ลบค่าที่เกิดขึ้นทั้งหมดจากรายการ Python

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list():
    for list in lists:
      if(list!=7):
         print(list)
remove_values_from_list()

ผลลัพธ์: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11

อีกวิธีหนึ่งคือ

lists = [6.9,7,8.9,3,5,4.9,1,2.9,7,9,12.9,10.9,11,7]
def remove_values_from_list(remove):
    for list in lists:
      if(list!=remove):
        print(list)
remove_values_from_list(7)

ผลลัพธ์: 6.9 8.9 3 5 4.9 1 2.9 9 12.9 10.9 11


"Python 'ซ้อนกันสำหรับแต่ละวงถ้า' ภายในฟังก์ชันที่ทำงานด้วยความแม่นยำ 100%!"
rafiqul786

คุณไม่ได้แก้ไขรายการที่คุณเพิ่งพิมพ์องค์ประกอบ นอกจากนี้การตั้งชื่อรายการที่มีความสับสน
kon Psych

0

หากคุณไม่ได้มีในตัวfilterหรือไม่ต้องการใช้พื้นที่เพิ่มเติมและคุณต้องการโซลูชันเชิงเส้น ...

def remove_all(A, v):
    k = 0
    n = len(A)
    for i in range(n):
        if A[i] !=  v:
            A[k] = A[i]
            k += 1

    A = A[:k]

0
hello =  ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
#chech every item for a match
for item in range(len(hello)-1):
     if hello[item] == ' ': 
#if there is a match, rebuild the list with the list before the item + the list after the item
         hello = hello[:item] + hello [item + 1:]
print hello

['สวัสดีชาวโลก']


โปรดอธิบายคำตอบของคุณอย่างละเอียดพร้อมคำอธิบาย
parlad

0

ฉันเพิ่งทำสิ่งนี้เพื่อรายการ ฉันเป็นแค่มือใหม่ โปรแกรมเมอร์ขั้นสูงขึ้นไปอีกเล็กน้อยสามารถเขียนฟังก์ชันเช่นนี้ได้

for i in range(len(spam)):
    spam.remove('cat')
    if 'cat' not in spam:
         print('All instances of ' + 'cat ' + 'have been removed')
         break

0

นอกจากนี้เรายังสามารถทำการลบทั้งหมดโดยใช้อย่างใดอย่างหนึ่งdelหรือpop:

import random

def remove_values_from_list(lst, target):
    if type(lst) != list:
        return lst

    i = 0
    while i < len(lst):
        if lst[i] == target:
            lst.pop(i)  # length decreased by 1 already
        else:
            i += 1

    return lst

remove_values_from_list(None, 2)
remove_values_from_list([], 2)
remove_values_from_list([1, 2, 3, 4, 2, 2, 3], 2)
lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)], 2)
print(len(lst))

ตอนนี้เพื่อประสิทธิภาพ:

In [21]: %timeit -n1 -r1 x = random.randrange(0,10)
1 loop, best of 1: 43.5 us per loop

In [22]: %timeit -n1 -r1 lst = [random.randrange(0, 10) for x in range(1000000)]
g1 loop, best of 1: 660 ms per loop

In [23]: %timeit -n1 -r1 lst = remove_values_from_list([random.randrange(0, 10) for x in range(1000000)]
    ...: , random.randrange(0,10))
1 loop, best of 1: 11.5 s per loop

In [27]: %timeit -n1 -r1 x = random.randrange(0,10); lst = [a for a in [random.randrange(0, 10) for x in
    ...:  range(1000000)] if x != a]
1 loop, best of 1: 710 ms per loop

ดังที่เราเห็นว่ารุ่นในสถานที่remove_values_from_list()ไม่ต้องการหน่วยความจำเพิ่มเติม แต่ใช้เวลาในการรันนานกว่านั้น:

  • 11 วินาทีสำหรับการลบค่าในที่
  • 710 milli secondsสำหรับ list comprehensions ซึ่งจะจัดสรรรายการใหม่ในหน่วยความจำ

0

ไม่มีใครโพสต์คำตอบที่ดีที่สุดสำหรับความซับซ้อนของเวลาและพื้นที่ดังนั้นฉันคิดว่าฉันจะให้มันยิง นี่คือโซลูชันที่ลบค่าที่เกิดขึ้นทั้งหมดโดยไม่ต้องสร้างอาร์เรย์ใหม่และในเวลาที่ซับซ้อนอย่างมีประสิทธิภาพ ข้อเสียเปรียบคือองค์ประกอบไม่รักษาความสงบเรียบร้อยคำสั่ง

ความซับซ้อนของเวลา: O (n)
ความซับซ้อนของพื้นที่เพิ่มเติม: O (1)

def main():
    test_case([1, 2, 3, 4, 2, 2, 3], 2)     # [1, 3, 3, 4]
    test_case([3, 3, 3], 3)                 # []
    test_case([1, 1, 1], 3)                 # [1, 1, 1]


def test_case(test_val, remove_val):
    remove_element_in_place(test_val, remove_val)
    print(test_val)


def remove_element_in_place(my_list, remove_value):
    length_my_list = len(my_list)
    swap_idx = length_my_list - 1

    for idx in range(length_my_list - 1, -1, -1):
        if my_list[idx] == remove_value:
            my_list[idx], my_list[swap_idx] = my_list[swap_idx], my_list[idx]
            swap_idx -= 1

    for pop_idx in range(length_my_list - swap_idx - 1):
        my_list.pop() # O(1) operation


if __name__ == '__main__':
    main()

-1

เกี่ยวกับความเร็ว!

import time
s_time = time.time()

print 'start'
a = range(100000000)
del a[:]
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 3.25

s_time = time.time()
print 'start'
a = range(100000000)
a = []
print 'finished in %0.2f' % (time.time() - s_time)
# start
# finished in 2.11

-3
p=[2,3,4,4,4]
p.clear()
print(p)
[]

เฉพาะกับ Python 3


2
เฮฮานี่อยู่ภายในขอบเขตของคำถามที่ถามและถูกต้อง
ริช

ฉันไม่เห็นว่ามันถูกต้อง การดำเนินการนี้จะลบรายการทั้งหมดออกจากรายการไม่ใช่การเกิดขึ้นของค่าทั้งหมด
Georgy

-3

มีอะไรผิดปกติกับ:

Motor=['1','2','2']
For i in Motor:
       If i  != '2':
       Print(i)
Print(motor)

ใช้อนาคอนดา


2
โปรดอธิบายบรรทัดโค้ดของคุณเพื่อให้ผู้ใช้รายอื่นเข้าใจการทำงานของมัน ขอบคุณ!
Ignacio Ara

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