Bir Python listesinden birden çok öğeyi tek bir ifadede kaldırın


115

Python'da, listeden öğeleri nasıl kaldıracağımı biliyorum.

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

Yukarıdaki bu kod, 5 ve "öğe" değerlerini item_list'ten kaldırır. Ancak kaldırılacak çok şey olduğunda, birçok satır yazmam gerekir.

item_list.remove("something_to_remove")

Ne kaldırdığımın dizinini biliyorsanız, şunu kullanırım:

del item_list[x]

burada x, kaldırmak istediğim öğenin dizinidir.

Kaldırmak istediğim tüm sayıların dizinini biliyorsam, endekslerdeki maddeler için bir çeşit döngü kullanacağım del.

Peki ya kaldırmak istediğim öğelerin indekslerini bilmiyorsam?

Denedim item_list.remove('item', 'foo')ama removesadece bir argüman gerektirdiğini söyleyen bir hata aldım .

Bir listeden birden çok öğeyi tek bir ifadede kaldırmanın bir yolu var mı?

PS Kullandım delve remove. Birisi bu ikisi arasındaki farkı açıklayabilir mi yoksa aynı mı?

Teşekkürler


1
İkinci sorunuzu cevaplamak için: delbir öğeyi indeksine göre siler. removeListenin fonksiyonu öğenin dizinini bulur ve sonra çağıran delbu dizin üzerinde.
Aaron Christiansen

Yanıtlar:


172

Python'da, yeni bir nesne oluşturmak genellikle var olanı değiştirmekten daha iyidir:

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

Aşağıdakilere eşdeğerdir:

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

Filtrelenmiş değerlerin büyük bir listesi olması durumunda (burada ('item', 5)küçük bir öğe kümesidir), işlem O (1) 'de setolduğu için a inkullanımı performans iyileştirmesine yol açabilir :

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

Yorumlarda açıklandığı ve burada önerildiği gibi, aşağıdakilerin her döngüde setin oluşturulmasını önleyerek daha fazla zaman kazandırabileceğini unutmayın:

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

Bir çiçek filtre bellek ucuz değilse de iyi bir çözümdür.


İlk cevabı beğendim. Yeni bir liste yapmıyorum ki bu iyi. Teşekkürler!
RandomCoder

Set python 2'de mi optimize edilmiş yoksa sadece python 3'te mi optimize edilmiş? Bununla küme, bayt kodu üretildiğinde yalnızca bir kez mi oluşturulur?
Har

Set, tanımı gereğiin operasyon için optimize edilmiştir . Dört ilkel veri yapısının karşılaştırmaları için bu ölçütlere bakın . Evet, set her döngüde oluşturulur, burada önerildiği gibi , sonuç olarak setin oluşturucu ifadesinde kullanılmak üzere özel bir değişkene kaydedilmesi zamandan tasarruf sağlayabilir.
aluriak

@RandomCoder Aslında yeni bir liste yaparsınız, sadece bir adı yeniden kullanırsınız. Bunu id(item_list)önce ve sonra karşılaştırarak kontrol edebilirsiniz item_list = [e for e in item_list if e not in ('item', 5)]. Bir listeyi yerinde nasıl değiştireceğinizi görmek için cevabımı kontrol edin.
Darkonaut

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

Çıkardıktan sonraki son liste aşağıdaki gibi olmalıdır

final_list=[3.14, True]

Tek Satır Kodu

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

çıktı aşağıdaki gibi olacaktır

final_list=[3.14, True]

13
hayır, listedeki öğeleri karıştırır. Yalnızca öğelerin sıralaması önemli değilse, ki bu oldukça sık yapar.
scavenger

5
Bu, kopyaları da listeden kaldıracaktır. Örnek listesi için önemli olduğundan değil
tschale

1
Bu cevap yanlıştır ve ciddi hatalara neden olabilir, neden oy verildi?
omerfarukdogan

1
Yinelenenleri kaldıracak! Cevap ciddi hatalara neden olabilir, lütfen kullanmayın.
user2698178

2

setPython'da s'nin inanılmaz yeteneğinden neden herkesin bahsetmeyi unuttuğunu bilmiyorum . Listenizi basitçe bir kümeye aktarabilir ve ardından kaldırmak istediğiniz şeyi şöyle basit bir ifadeyle kaldırabilirsiniz:

>>> 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
Yine de nesnelerin sırasını korumaz.
Astrid

Ayrıca listede bulunma olasılığı bulunan kopyaları da kaldırır.
kyriakosSt

1

Cevabımı buradan tekrar gönderiyorum çünkü buraya da uyduğunu gördüm. Birden fazla değeri kaldırmaya veya bu değerlerin yalnızca kopyalarını kaldırmaya izin verir ve yeni bir liste döndürür veya verilen listeyi yerinde değiştirir.


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

Docstring uzantısı:

"""
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']
"""

Gerçekten ne yapmak istediğiniz konusunda net olmalısınız, mevcut bir listeyi değiştirmelisiniz veya eksik belirli öğelerle yeni bir liste oluşturmalısınız. Mevcut listeye işaret eden ikinci bir referansınız olması durumunda bu ayrımı yapmanız önemlidir. Örneğin, varsa ...

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]

İstediğiniz davranış bu olabilir veya olmayabilir.


1

Sen kullanabilirsiniz filterfalse gelen işlevi itertools modülü

Misal

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=}")

Çıktı:

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

Peki ya kaldırmak istediğim öğelerin indekslerini bilmiyorsam?

Neden .remove'dan hoşlanmadığınızı tam olarak anlamıyorum ama .index (değer) kullanım değerine karşılık gelen ilk dizini almak için:

ind=item_list.index('item')

daha sonra ilgili değeri kaldırın:

del item_list.pop[ind]

.index (değer) değerin ilk oluşumunu alır ve .remove (değer) değerin ilk oluşumunu kaldırır


Sonuç değerine ihtiyacınız yoksa del item_list[ind]bunun yerine kullanmayı düşünün pop.
kojiro

-1

Bunu kullanabilirsin -

Bir listemiz olduğunu varsayalım, l = [1,2,3,4,5]

Son iki öğeyi tek bir ifadede silmek istiyoruz

del l[3:]

Çıktımız var:

l = [1,2,3]

Basit Tutun

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.