Xóa nhiều mục khỏi danh sách Python chỉ trong một câu lệnh


107

Trong python, tôi biết cách xóa các mục khỏi danh sách.

item_list = ['item', 5, 'foo', 3.14, True]
item_list.remove('item')
item_list.remove(5)

Đoạn mã trên sẽ xóa các giá trị 5 và 'item' khỏi item_list. Nhưng khi có nhiều thứ cần loại bỏ, tôi phải viết nhiều dòng

item_list.remove("something_to_remove")

Nếu tôi biết chỉ mục của những gì tôi đang xóa, tôi sử dụng:

del item_list[x]

trong đó x là chỉ mục của mục tôi muốn xóa.

Nếu tôi biết chỉ mục của tất cả các số mà tôi muốn loại bỏ, tôi sẽ sử dụng một số loại vòng lặp cho delcác mục tại chỉ số.

Nhưng điều gì sẽ xảy ra nếu tôi không biết chỉ số của các mục tôi muốn xóa?

Tôi đã thử item_list.remove('item', 'foo')nhưng gặp lỗi khi nói rằng removechỉ cần một đối số.

Có cách nào để xóa nhiều mục khỏi danh sách trong một câu lệnh không?

PS tôi đã sử dụng delremove. Ai đó có thể giải thích sự khác biệt giữa hai điều này, hoặc chúng giống nhau?

Cảm ơn


1
Để trả lời câu hỏi thứ hai của bạn: delxóa một mục theo chỉ mục của nó. Các removechức năng của một danh sách tìm thấy chỉ số của một mục và sau đó gọi delvào số đó.
Aaron Christiansen

Có thể trùng lặp của Xóa nhiều yếu tố từ danh sách
IMLD

Câu trả lời:


159

Trong Python, tạo một đối tượng mới thường tốt hơn là sửa đổi một đối tượng hiện có:

item_list = ['item', 5, 'foo', 3.14, True]
item_list = [e for e in item_list if e not in ('item', 5)]

Tương đương với:

item_list = ['item', 5, 'foo', 3.14, True]
new_list = []
for e in item_list:
    if e not in ('item', 5):
        new_list.append(e)
item_list = new_list

Trong trường hợp có một danh sách lớn các giá trị được lọc ra (ở đây, ('item', 5)là một tập hợp nhỏ phần tử), sử dụng a setcó thể dẫn đến cải thiện hiệu suất, vì inhoạt động trong O (1):

item_list = [e for e in item_list if e not in {'item', 5}]

Lưu ý rằng, như được giải thích trong các nhận xét và đề xuất ở đây , những điều sau đây có thể tiết kiệm thời gian hơn nữa, tránh tập hợp được tạo ở mỗi vòng lặp:

unwanted = {'item', 5}
item_list = [e for e in item_list if e not in unwanted]

Một bộ lọc nở cũng là một giải pháp tốt nếu bộ nhớ không rẻ.


Tôi thích câu trả lời đầu tiên. Tôi không lập danh sách mới, điều đó tốt. Cảm ơn!
RandomCoder

Bộ được tối ưu hóa trong python 2 hay nó chỉ được tối ưu hóa trong python 3? Ý tôi là tập hợp chỉ được tạo một lần khi mã bytecode được tạo?
Har

Set là, theo định nghĩa , tối ưu hóa cho inhoạt động. Xem điểm chuẩn này để so sánh bốn cấu trúc dữ liệu ban đầu. Có, tập hợp được tạo ở mỗi vòng lặp, như được đề xuất ở đây , do đó, lưu tập hợp trong một biến chuyên dụng để sử dụng trong biểu thức trình tạo có thể tiết kiệm thời gian.
aluriak

@RandomCoder Bạn thực sự tạo một danh sách mới, bạn chỉ cần sử dụng lại tên. Bạn có thể kiểm tra điều này bằng cách so sánh id(item_list)trước và sau item_list = [e for e in item_list if e not in ('item', 5)]. Kiểm tra câu trả lời của tôi để xem cách sửa đổi danh sách tại chỗ.
Darkonaut

20
item_list = ['item', 5, 'foo', 3.14, True]
list_to_remove=['item', 5, 'foo']

danh sách cuối cùng sau khi loại bỏ sẽ như sau

final_list=[3.14, True]

Mã dòng đơn

final_list= list(set(item_list).difference(set(list_to_remove)))

đầu ra sẽ như sau

final_list=[3.14, True]

13
nope, nó xáo trộn các mục trong danh sách. Chỉ sử dụng nếu thứ tự các mục không quan trọng, điều này thường xảy ra.
người nhặt rác

5
Điều này cũng sẽ loại bỏ các bản sao khỏi danh sách. Không phải là nó mang đầy đủ các ví dụ danh sách mặc dù
tschale

1
Câu trả lời này không chính xác và có thể gây ra lỗi nghiêm trọng, tại sao nó lại được ủng hộ?
omerfarukdogan

1
Nó sẽ loại bỏ các bản sao! Câu trả lời có thể gây ra lỗi nghiêm trọng, vui lòng không sử dụng.
user2698178

2

Tôi không biết tại sao mọi người lại quên đề cập đến khả năng tuyệt vời của sets trong python. Bạn có thể chỉ cần chuyển danh sách của mình thành một tập hợp và sau đó xóa bất kỳ thứ gì bạn muốn xóa trong một biểu thức đơn giản như sau:

>>> item_list = ['item', 5, 'foo', 3.14, True]
>>> item_list = set(item_list) - {'item', 5}
>>> item_list
{True, 3.14, 'foo'}
>>> # you can cast it again in a list-from like so
>>> item_list = list(item_list)
>>> item_list
[True, 3.14, 'foo']

6
Không duy trì thứ tự của các đối tượng mặc dù.
Astrid

Và cũng sẽ loại bỏ các bản sao có khả năng tồn tại trong danh sách.
kyriakosSt

1

Tôi đăng lại câu trả lời của mình từ đây vì tôi thấy nó cũng phù hợp ở đây. Nó cho phép loại bỏ nhiều giá trị hoặc chỉ loại bỏ các bản sao của các giá trị này và trả về một danh sách mới hoặc sửa đổi danh sách đã cho tại chỗ.


def removed(items, original_list, only_duplicates=False, inplace=False):
    """By default removes given items from original_list and returns
    a new list. Optionally only removes duplicates of `items` or modifies
    given list in place.
    """
    if not hasattr(items, '__iter__') or isinstance(items, str):
        items = [items]

    if only_duplicates:
        result = []
        for item in original_list:
            if item not in items or item not in result:
                result.append(item)
    else:
        result = [item for item in original_list if item not in items]

    if inplace:
        original_list[:] = result
    else:
        return result

Phần mở rộng chuỗi tài liệu:

"""
Examples:
---------

    >>>li1 = [1, 2, 3, 4, 4, 5, 5]
    >>>removed(4, li1)
       [1, 2, 3, 5, 5]
    >>>removed((4,5), li1)
       [1, 2, 3]
    >>>removed((4,5), li1, only_duplicates=True)
       [1, 2, 3, 4, 5]

    # remove all duplicates by passing original_list also to `items`.:
    >>>removed(li1, li1, only_duplicates=True)
      [1, 2, 3, 4, 5]

    # inplace:
    >>>removed((4,5), li1, only_duplicates=True, inplace=True)
    >>>li1
        [1, 2, 3, 4, 5]

    >>>li2 =['abc', 'def', 'def', 'ghi', 'ghi']
    >>>removed(('def', 'ghi'), li2, only_duplicates=True, inplace=True)
    >>>li2
        ['abc', 'def', 'ghi']
"""

Bạn nên nói rõ những gì bạn thực sự muốn làm, sửa đổi danh sách hiện có hoặc tạo danh sách mới với các mục cụ thể bị thiếu. Điều quan trọng là phải tạo ra sự khác biệt đó trong trường hợp bạn có tham chiếu thứ hai trỏ đến danh sách hiện có. Ví dụ, nếu bạn có ...

li1 = [1, 2, 3, 4, 4, 5, 5]
li2 = li1
# then rebind li1 to the new list without the value 4
li1 = removed(4, li1)
# you end up with two separate lists where li2 is still pointing to the 
# original
li2
# [1, 2, 3, 4, 4, 5, 5]
li1
# [1, 2, 3, 5, 5]

Đây có thể là hành vi bạn muốn.


1

Bạn có thể sử dụng hàm filterfalse từ mô-đun itertools

Thí dụ

import random
from itertools import filterfalse

random.seed(42)

data = [random.randrange(5) for _ in range(10)]
clean = [*filterfalse(lambda i: i == 0, data)]
print(f"Remove 0s\n{data=}\n{clean=}\n")


clean = [*filterfalse(lambda i: i in (0, 1), data)]
print(f"Remove 0s and 1s\n{data=}\n{clean=}")

Đầu ra:

Remove 0s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 1, 1, 1, 4, 4]

Remove 0s and 1s
data=[0, 0, 2, 1, 1, 1, 0, 4, 0, 4]
clean=[2, 4, 4]

0

Nhưng điều gì sẽ xảy ra nếu tôi không biết chỉ số của các mục tôi muốn xóa?

Tôi không hiểu chính xác tại sao bạn không thích .remove nhưng để lấy chỉ mục đầu tiên tương ứng với một giá trị sử dụng .index (value):

ind=item_list.index('item')

sau đó xóa giá trị tương ứng:

del item_list.pop[ind]

.index (value) nhận lần xuất hiện đầu tiên của giá trị và .remove (value) loại bỏ lần xuất hiện đầu tiên của giá trị


Cân nhắc sử dụng del item_list[ind]thay vì popnếu bạn không cần giá trị kết quả.
kojiro

-1

Bạn có thể sử dụng cái này -

Giả sử chúng ta có một danh sách, l = [1,2,3,4,5]

Chúng tôi muốn xóa hai mục cuối cùng trong một câu lệnh

del l[3:]

Chúng tôi có đầu ra:

l = [1,2,3]

Giữ nó đơn giản

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.