簡體   English   中英

將一個列表中的所有元素與另一個列表保持一致

[英]Keep all elements in one list from another

我有兩個列表trainkeep ,后者包含獨特的元素,例如

train = [1, 2, 3, 4, 5, 5, 5, 5, 3, 2, 1]
keep = [1, 3, 4]

有沒有辦法創建一個新列表,其中包含keep使用setstrain所有元素? 最終結果應該是:

train_keep = [1, 3, 4, 3, 1]

目前我正在使用itertools.filterfalse from how to keep a list of elements based on another list但它慢,因為列表很大......

將列表keep轉換為set ,因為它將經常檢查。 迭代train ,因為您想保持順序並重復。 這使得set不是一個選項。 即使是這樣,也無濟於事,因為無論如何迭代都必須發生:

keeps = set(keep)
train_keep = [k for k in train if k in keeps]

一個懶惰的,可能更慢的版本會像

train_keep = filter(lambda x: x in keeps, train)

這些選項都不會給你帶來很大的加速,你可能最好使用 numpy 或 pandas 或其他一些在 C 中實現循環並將數字存儲為比完整的 python 對象更簡單的庫。 這是一個示例 numpy 解決方案:

train = np.array([...])
keep = np.array([...])
train_keep = train[np.isin(train, keep)]

這可能是一個O(M * N)算法而不是O(M)集查找,但是如果檢查keep N元素比名義上的O(1)查找快,那么你就贏了。

您可以使用排序查找獲得更接近O(M log(N))東西:

train = np.array([...])
keep = np.array([...])
keep.sort()

ind = np.searchsorted(keep, train, side='left')
ind[ind == keep.size] -= 1
train_keep = train[keep[ind] == train]

更好的替代方法可能是將np.inf或最大越界整數附加到已排序的keep數組中,這樣您就不np.inf缺失與extra邊緣元素區分開來。 np.max(train.max() + 1, keep.max())這樣的東西會做:

train = np.array([...])
keep = np.array([... 99999])
keep.sort()

ind = np.searchsorted(keep, train, side='left')
train_keep = train[keep[ind] == train]

對於train.size = 10000keep.size = 10隨機輸入,numpy 方法在我的筆記本電腦上快約 10 倍。

>>> keep_set = set(keep)
>>> [val for val in train if val in keep_set]
[1, 3, 4, 3, 1]

請注意,如果keep很小,則將其轉換為set可能沒有任何性能優勢(以確保為基准)。

這是一個選項:

train = [1, 2, 3, 4, 5, 5, 5, 5, 3, 2, 1]
keep = [1, 3, 4]

keep_set = set(keep)
res = [item for item in train if item in keep_set]
# [1, 3, 4, 3, 1]

我使用keep_set來加快查找速度。

邏輯是相同的,但請嘗試一下,對於您的情況,生成器可能更快:

def keep_if_in(to_keep, ary):
  for element in ary:
    if element in to_keep:
      yield element

train = [1, 2, 3, 4, 5, 5, 5, 5, 3, 2, 1]
keep = [1, 3, 4]
train_keep = keep_if_in(set(keep), train)

最后,在需要時轉換為列表或直接迭代生成器:

print(list(train_keep))

#  alternatively, uncomment this and comment out the line above,
#  it's because a generator can be consumed once
#  for e in train_keep:
#    print(e)

這是對 Mad Physicist 的巧妙技巧的略微擴展,以涵蓋列表包含字符且其中一個是數據框列的情況(我試圖在數據框中查找項目列表,包括所有重復項,但顯而易見的答案是, mylist.isin(df['col')刪除了重復項)。 我調整了他的回答來處理 Numpy 可能截斷字符數據的問題。

#Sample dataframe with strings
d = {'train': ['ABC_S8#Q09#2#510a#6','ABC_S8#Q09#2#510l','ABC_S8#Q09#2#510a#6','ABC_S8#Q09#2#510d02','ABC_S8#Q09#2#510c#8y','ABC_S8#Q09#2#510a#6'], 'col2': [1,2,3,4,5,6]}
df = pd.DataFrame(data=d)

keep_list = ['ABC_S8#Q09#2#510a#6','ABC_S8#Q09#2#510b13','ABC_S8#Q09#2#510c#8y']

#Make sure the Numpy datatype accomodates longest string in either list
maxlen = max(len(max(keep_list, key = len)),len(max(df['train'], key = len))) 
strtype = '<U'+ str(maxlen) 

#Convert lists to Numpy arrays
keep = np.array(keep_list,dtype = strtype)
train = np.array(df['train'],dtype = strtype)

#Algorithm
keep.sort()
ind = np.searchsorted(keep, train, side='left')
ind[ind == keep.size] -= 1
train_keep = df[keep[ind] == df['train']] #reference the original dataframe

我發現這比我嘗試過的其他解決方案要快得多。

暫無
暫無

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

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