如果列表项在另一个列表中,如何在保持顺序的同时将列表项移到前面
我有两个示例列表,
vals = ["a", "c", "d", "e", "f", "g"]
xor = ["c", "g"]
我想vals根据xor列表对列表进行排序,即,中的值xor应按vals确切顺序排在列表的首位。中存在的其余值vals应保持相同的顺序。
此外,在这些情况下,值xor可能不在,vals只是忽略这些值。而且,在重复的情况下,我只需要一个值。
期望的输出:
vals = ["c", "g", "a", "d", "e", "f"]
# here a, d, e, f are not in xor so we keep them in same order as found in vals.
我的方法:
new_list = []
for x in vals:
for y in xor:
if x == y:
new_list.append(x)
for x in vals:
if x not in xor:
new_list.append(x)
该vals列表目前有大约 80 万个单词或短语。该xor列表有 30 万个单词或短语,但以后可能会增加。有些短语也有点长。解决问题的最有效方法是什么?
回答
构建 indeces 的 order dictxor并将其用作排序键:
order = {n: i for i, n in enumerate(xor)}
sorted(vals, key=lambda x: order.get(x, len(xor)))
# ['c', 'g', 'a', 'd', 'e', 'f']
使用len(vals)作为默认值,确保所有值不是xor会在后面结束。这当然假定,您要的数值是在xor基于他们的顺序进行排序xor(制作过程O(M+NlogN))。否则你可以更快(O(M+N)):
from operator import contains
from functools import partial
s = set(xor)
result = list(filter(partial(contains, s), vals))
result.extend(v for v in vals if v not in s)
或者以更易读的方式:
s = set(xor)
result = [v for v in vals if v in s]
result += (v for v in vals if v not in s)