繁体   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