簡體   English   中英

列表和集合之間的差運算符

[英]Difference operator between a List and a Set

是否有操作員根據Set的內容從List刪除元素?

通過此操作,我想做的事情已經可以實現:

words = ["hello", "you", "how", "are", "you", "today", "hello"]
my_set = {"you", "are"}

new_list = [w for w in words if w not in my_set]
# ["hello", "how", "today", "hello"]

這個列表理解讓我感到困擾的是,對於龐大的集合,它對我而言似乎不如可以在兩個集合之間使用的-運算符有效。 因為在列表理解中,迭代是在Python中進行的,而對於運算符,迭代是在C並且級別較低,因此速度更快。

因此,有什么方法可以比使用列表理解更短/更干凈/更有效的方式來計算列表和集合之間的差異,例如:

# I know this is not possible, but does something approaching exist?
new_list = words - my_set

TL; DR

我正在尋找一種方法來從List移除Set存在的所有元素,即:

  • 清潔劑(也許內置)
  • 和/或更有效

比我所知道的列表理解能力更勝一籌。

不幸的是,唯一的答案是:不,對於這種操作,沒有以本機代碼實現的內置方法。

這個列表理解讓我感到困擾的是,對於龐大的集合,它對我而言似乎不如可以在兩個集合之間使用的-運算符有效。

我認為這里重要的是“外觀”部分。 是的,列表理解在Python中的運行要比固定的運行更多,但是我假設您的大多數應用程序實際上在Python中運行(否則,您可能應該使用C編程)。 因此,您應該考慮這是否真的很重要。 在Python中遍歷列表非常快,並且對集合的成員資格測試也非常快(固定時間並以本機代碼實現)。 而且,如果您查看列表理解,它們也非常快。 因此,這可能無關緊要。

因為在列表理解中,迭代是在Python中進行的,而對於運算符,迭代是在C中進行的,並且級別較低,因此速度更快。

的確,本機操作速度更快,但它們也更加專業,受限且靈活性較低。 對於布景,區別很容易。 設定差是一個數學概念,非常明確地定義。

但是,當談論“列表差異”或“列表和集合差異”(或更籠統的“列表和可迭代差異”?)時,它變得更加不清楚。 有很多懸而未決的問題:

  • 如何處理重復項? 如果原始列表中有兩個X ,而子列表中只有一個X ,則兩個X都應該從列表中消失嗎? 應該只有一個消失嗎? 如果是這樣,哪個,為什么?

  • 訂單如何處理? 訂單應保留在原始清單中嗎? 換位中元素的順序是否有影響?

  • 如果我們想基於除平等以外的其他條件減去成員,該怎么辦? 對於集合,很明顯,它們始終對成員的相等性(和哈希值)起作用。 列表沒有,因此列表在設計上要靈活得多。 通過列表理解,我們可以輕松地具有從列表中刪除元素的任何條件。 如果存在“列表差異”,我們將被限制為平等,如果您考慮一下,那實際上可能是一種罕見的情況。

    如果您需要計算差異(甚至是一些有序集合 ),則更有可能使用集合 而且對於過濾列表,在少數情況下,您可能希望以過濾列表結尾,因此使用生成器表達式(或Python 3 filter()函數)並在以后不使用該表達式的情況下使用它可能更常見。必須在內存中創建該過濾列表。

我要說的是,列表差異的用例不像集合差異那么清楚。 而且,如果有一個用例,那可能是一個非常罕見的用例。 通常,我認為不應該為此增加Python實現的復雜性。 尤其是在Python中的替代方法(例如列表理解)達到既定速度的情況下。

首先,您是否過早擔心優化問題並不是真正的問題? 在進入此操作范圍之前,我必須擁有至少包含10,000,000個元素的列表,而這些操作需要花費1/10秒的時間。

如果您使用的是大型數據集,那么使用numpy可能會比較有利。

import random
import timeit

r = range(10000000)

setup = """
import numpy as np
l = list({!r})
s = set(l)
to_remove = {!r}
n = np.array(l)
n_remove = np.array(list(to_remove))
""".format(r, set(random.sample(r, 3)))

list_filter = "[x for x in l if x not in to_remove]"
set_filter = "s - to_remove"
np_filter = "n[np.in1d(n, n_remove, invert=True)]"

n = 1
l_time = timeit.timeit(list_filter, setup, number=n)
print("lists:", l_time)
s_time = timeit.timeit(set_filter, setup, number=n)
print("sets:", s_time)
n_time = timeit.timeit(np_filter, setup, number=n)
print("numpy:", n_time)

返回以下結果-numpy比使用set快一個數量級。

lists: 0.8743789765043315
sets: 0.20703006886620656
numpy: 0.06197169088128707

我同意戳。 這是我的理由:

最簡單的方法是使用filter

words = ["hello", "you", "how", "are", "you", "today", "hello"]
my_set = {"you", "are"}

new_list = filter(lambda w: w not in my_set, words)

使用Dunes解決方案,我得到了以下時間:

lists:  0.87401028
sets:   0.55103887
numpy:  0.16134396
filter: 0.00000886 WOW beats numpy by various orders of magnitude !!!

但是,等等,我們進行了一個有缺陷的比較,因為我們正在嚴格比較創建列表的時間(理解和設置差異)與延遲創建列表的時間(numpy和filter)。

如果我運行Dunes解決方案但生成實際列表,則會得到:

lists:  0.86804159
sets:   0.56945663  
numpy:  1.19315723
filter: 1.68792561

現在numpy的效率比使用簡單的filter略高,但是兩者都不比列表理解更好,后者是第一個也是更直觀的解決方案。

我肯定會使用filter過的理解,除非我需要使用過濾列表中不止一次(雖然我可以tee的話)。

暫無
暫無

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

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