下面是在普通Python中這樣做的合理有效方法。我們使用函數not_seen
來測試元組是否包含已經在接受的元組中看到的元素。
all_tups = [(1, 2), (2, 1), (3, 4), (3, 5), (4, 3), (6, 8), (6, 7), (7, 9)]
def not_seen(t, seen=set()):
if t[0] in seen or t[1] in seen:
return False
seen.update(t)
return True
unique = list(filter(not_seen, all_tups))
print(unique)
輸出
[(1, 2), (3, 4), (6, 8), (7, 9)]
有與not_seen
一個小問題:它採用的是默認的可變參數seen
緩存看到的元素,並集不能被清除,因此,如果您需要執行這個操作再次seen
仍然會保留舊的元素。我們可能使得seen
是一個全球性的,但那會運行得更慢。另一種選擇是每次我們需要一個工廠函數來生成一個乾淨版本的seen
。例如:
def make_checker():
def not_seen(t, seen=set()):
if t[0] in seen or t[1] in seen:
return False
seen.update(t)
return True
return not_seen
not_seen = make_checker()
FWIW,這裏有not_seen
壓縮版本;它應該是差不多與原始效率一樣高,如果它實際上更快,我會感到驚訝。 :)
def not_seen(t, seen=set()):
return False if t[0] in seen or t[1] in seen else seen.update(t) or True
我們可以在緊湊型轉換成拉姆達,然後我們就不必擔心清除seen
集的問題。
all_tups = [(1, 2), (2, 1), (3, 4), (3, 5), (4, 3), (6, 8), (6, 7), (7, 9)]
unique = list(filter(lambda t, seen=set():
False if t[0] in seen or t[1] in seen else seen.update(t) or True, all_tups))
print(unique)
這裏是一個NumPy的實現。首先我們將數據轉換爲2D Numpy數組。然後,我們使用not_seen
和numpy.apply_along_axis
創建一個Numpy布爾數組,表示應接受的對,然後使用該布爾數組來選擇所需的對。
import numpy as np
def not_seen(t, seen=set()):
if t[0] in seen or t[1] in seen:
return False
seen.update(t)
return True
all_tups = [(1, 2), (2, 1), (3, 4), (3, 5), (4, 3), (6, 8), (6, 7), (7, 9)]
all_tups = np.array(all_tups)
print(all_tups, all_tups.dtype)
print('- ' * 20)
filtered = all_tups[np.apply_along_axis(not_seen, 1, all_tups)]
print(filtered)
輸出
[[1 2]
[2 1]
[3 4]
[3 5]
[4 3]
[6 8]
[6 7]
[7 9]] int32
- - - - - - - - - - - - - - - - - - - -
[[1 2]
[3 4]
[6 8]
[7 9]]
這應該比上述普通Python實現更快。循環過程本身應該更快,瓶頸是我們仍然調用not_seen
這是一個普通的Python函數。此外,它使用更多的RAM,因爲它必須構造布爾數組。
更新
這是實際上可以從not_seen
功能外清除seen
集。我們可以通過訪問其.__default__
屬性函數的默認參數(或舊版本的Python 2 .func_defaults
; .__default__
作品在Python 2.6,而不是2.5)。
例如,
not_seen.__defaults__[0].clear()
什麼是這裏的冷凍集的目的是什麼?爲什麼不直接使用元組呢? –
這更多的是在黑暗中獲取獨特的元組,但仍然沒有給出我想要的輸出。 – Tanuj
我的意思是,你可能只是做了'{在all_tups TUP TUP爲}' –