簡體   English   中英

如果該子列表中的任何元素在另一個列表中,如何刪除列表中的列表(即子列表)?

[英]how to delete a list within a list (i.e., a sublist) if any element of that sublist is in another list?

我有一個包含許多子列表的列表。 例如:

full_list = [[1, 1, 3, 4], [3, 99, 5, 2],[2, 4, 4], [3, 4, 5, 2, 60]]

我還有另一個列表,名為省略。 例如:

omit = [99, 60, 98]

如果該子列表中的任何元素在省略列表中,我想刪除full_list中的子列表。 例如,我希望結果列表是:

reduced_list = [[1, 1, 3, 4], [2, 4, 4]]

因為只有這些子列表沒有省略列表中的元素。

我猜是有一些簡單的方法可以通過列表理解來解決這個問題,但我無法讓它工作。 我嘗試了很多東西:例如:

reduced_list = [sublist for sublist in full_list if item for sublist not in omit] 
  • 這段代碼導致錯誤(無效的snytax) - 但我想我錯過了更多。

任何幫助將非常感激!

ps,以上是一個簡化的問題。 我的最終目標是從非常長的列表(例如,500,000個子列表)中刪除子列表,如果這些子列表中的任何元素(字符串)在“省略”列表中包含超過2000個字符串。

使用setall()

>>> omit = {99, 60, 98}
>>> full_list = [[1, 1, 3, 4], [3, 99, 5, 2],[2, 4, 4], [3, 4, 5, 2, 60]]
>>> [item for item in full_list if all(x not in omit for x in item)]
[[1, 1, 3, 4], [2, 4, 4]]

這種方法與@ alecxe(或@ÓscarLópez)解決方案的主要區別在於它all短路並且不會在內存中創建任何集合或列表,而set-intersection返回包含所有常見項目的新集合omit set並檢查它的長度以確定是否有任何項目是常見的。(set-intersection以C速度內部發生,因此它比all常規python循環更快)

時間比較:

>>> import random

沒有項目相交:

>>> omit = set(random.randrange(1, 10**18) for _ in xrange(100000))
>>> full_list = [[random.randrange(10**19, 10**100) for _ in xrange(100)] for _ in xrange(1000)]

>>> %timeit [item for item in full_list if not omit & set(item)]
10 loops, best of 3: 43.3 ms per loop
>>> %timeit [x for x in full_list if not omit.intersection(x)]
10 loops, best of 3: 28 ms per loop
>>> %timeit [item for item in full_list if all(x not in omit for x in item)]
10 loops, best of 3: 65.3 ms per loop

所有項目相交:

>>> full_list = [range(10**3) for _ in xrange(1000)]
>>> omit = set(xrange(10**3))
>>> %timeit [item for item in full_list if not omit & set(item)]
1 loops, best of 3: 148 ms per loop
>>> %timeit [x for x in full_list if not omit.intersection(x)]
1 loops, best of 3: 108 ms per loop
>>> %timeit [item for item in full_list if all(x not in omit for x in item)]
100 loops, best of 3: 1.62 ms per loop

有些項目相交:

>>> omit = set(xrange(1000, 10000))
>>> full_list = [range(2000) for _ in xrange(1000)]
>>> %timeit [item for item in full_list if not omit & set(item)]
1 loops, best of 3: 282 ms per loop
>>> %timeit [x for x in full_list if not omit.intersection(x)]
1 loops, best of 3: 159 ms per loop
>>> %timeit [item for item in full_list if all(x not in omit for x in item)]
1 loops, best of 3: 227 ms per loop

試試這個:

full_list = [[1, 1, 3, 4], [3, 99, 5, 2], [2, 4, 4], [3, 4, 5, 2, 60]]
omit = frozenset([99, 60, 98])
reduced_list = [x for x in full_list if not omit.intersection(x)]

我對輸入數據所做的唯一改變是omit現在是一個集合,出於效率原因,因為它將允許我們執行快速交集(它被凍結,因為我們不打算修改它),注意x不不得不是一套。 現在, reduced_list變量將包含預期值:

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

omit一個集合,檢查每個迭代步驟的交集:

>>> full_list = [[1, 1, 3, 4], [3, 99, 5, 2],[2, 4, 4], [3, 4, 5, 2, 60]]
>>> omit = [99, 60, 98]
>>> omit = set(omit)  # or just omit = {99, 60, 98} for python >= 2.7
>>> [item for item in full_list if not omit & set(item)]
[[1, 1, 3, 4], [2, 4, 4]]

僅供參考,@ frozenset建議,最好使用frozenset代替套裝。 使用frozenset它運行得更快:

import timeit


def omit_it(full_list, omit):
    return [item for item in full_list if not omit & set(item)]

print timeit.Timer('omit_it([[1, 1, 3, 4], [3, 99, 5, 2],[2, 4, 4], [3, 4, 5, 2, 60]], {99, 60, 98})',
                   'from __main__ import omit_it').timeit(10000)

print timeit.Timer('omit_it([[1, 1, 3, 4], [3, 99, 5, 2],[2, 4, 4], [3, 4, 5, 2, 60]], frozenset([99, 60, 98]))',
                   'from __main__ import omit_it').timeit(10000)

打印:

0.0334849357605
0.0319349765778

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM