Python 如果列表项位于另一个列表中,如何在保持顺序的同时将其移到前面
我有两个示例列表Python 如果列表项位于另一个列表中,如何在保持顺序的同时将其移到前面,python,Python,我有两个示例列表 vals = ["a", "c", "d", "e", "f", "g"] xor = ["c", "g"] 我想根据xor列表对vals列表进行排序, i、 例如,xor中的值应按精确顺序放在vals列表的第一位。VAL中的其余值应保持相同顺序 另外,xor中的值可能不在vals中,在这些情况下,只需忽略这些值即
vals = ["a", "c", "d", "e", "f", "g"]
xor = ["c", "g"]
我想根据xor
列表对vals
列表进行排序,
i、 例如,xor
中的值应按精确顺序放在vals
列表的第一位。VAL
中的其余值应保持相同顺序
另外,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
列表目前约有800k个单词或短语。xor
列表有300k个单词或短语,但以后可能会增加。有些短语也有点长。解决此问题的最有效方法是什么?在xor
中构建索引的顺序dict,并将其用作排序键:
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)
):
或者以更具可读性的方式:
s = set(xor)
result = [v for v in vals if v in s]
result += (v for v in vals if v not in s)
这也应该是您的一线解决方案:
vals = [1, 2, 5, 4, 3, 2, 11, 6]
xor = [10, 11]
new_list = xor + [elem for elem in vals if elem not in xor]
(编辑:不带已排序和正确的变量)附加
xor
中也存在于vals
中的所有值,以及xor
中不存在的vals
的所有值的列表:
sorted_list = [v for v in xor if v in vals] + [v for v in vals if v not in xor]
另一种方法:
output = list(filter(lambda x: x in vals, xor)) + list(filter(lambda x: x not in xor, vals))
鉴于问题中添加的澄清,此处发布的一些答案实际上没有提供预期的答案,其他答案也没有效率 一种解决方案是采用@dreamcrash的答案,但使用集合进行查找:
def order_by1(vals, xor):
set_vals = set(vals)
set_xor = set(xor)
return [v for v in xor if v in set_vals] + [v for v in vals if v not in set_xor]
这将通过在循环的每次迭代中删除耗时的()列表查找来提高效率
由于您不关心在xor
中找不到的值的顺序,因此此操作的一个变体是用set操作替换第二个列表理解:
def order_by2(vals, xor):
set_vals = set(vals)
return [v for v in xor if v in set_vals] + list(set_vals - set(xor))
另一个解决方案是使用
有序的集合在引擎盖下使用字典。我们可以直接使用字典,利用以下事实:
另一个真正做到所需的解决方案是@schwobasegl答案中的第一个。使用800000个和300000个随机短语列表对这些短语进行计时,其中150000个重叠:
import random
import string
import timeit
def random_phrase():
return "".join(random.choices(string.ascii_letters, k=10))
def generate_lists(M, N, overlap):
a = [random_phrase() for _ in range(M)]
b = ([random_phrase() for _ in range(N - overlap)] +
random.sample(a, k=overlap))
random.shuffle(b)
return a, b
def dreamcrash(vals, xor):
return [v for v in xor if v in vals] + [v for v in vals if v not in xor]
def schwobaseggl(vals, xor):
order = {n: i for i, n in enumerate(xor)}
len_xor = len(xor) # saves some time when sorting
return sorted(vals, key=lambda x: order.get(x, len_xor))
vals, xor = generate_lists(800000, 300000, overlap=150000) # this takes a while
for f in [dreamcrash, order_by1, order_by2, order_by3, order_by4, schwobaseggl]:
print(f, end='...')
print(timeit.timeit(stmt=f"{f.__name__}(vals, xor)", number=1, globals=globals()))
我放弃了计时
dreamcrash
,因为时间太长了order\u by2
似乎速度最快,其次是order\u by4
,order\u by1
,和schwobasegl
,在我的电脑上每种时间大约为.5-1.5s。有序集解决方案要慢得多。检查集合是否包含项,以及在字典中设置项,这都解释了为什么字典和基于集合的版本具有相似的性能。另一种排序方法:
vals.sort(key=set(xor).__contains__, reverse=True)
我怀疑它比其他的更快,但是我不想尝试创建可能与实际数据相似的测试数据。(部分原因是您的问题还不完全清楚。我将讨论您的参考实现的功能,即两个组在
VAL
中保持顺序)此方法的时间复杂性是什么?我有一个巨大的列表。O(M+NlogN)
具有M
大小为xor
和N
大小为vals
。我不想对“vals”中的值进行排序,在xor中找不到的vals中的其他值应该保持相同的顺序。不要使用像这样的dunder方法this@schwobaseggl然后是类似于partial的东西(operator.contains,a))
会更好。我冒昧地编辑了一下,现在应该修好了。这是一个简单的列表生成问题。从他所说的来看,并不清楚他是否希望它们出现在最终的列表中。从技术上讲,您可以使用另一个列表生成器来实现这一点,而不是在开始时使用xor列表。第二种方法的时间复杂度是多少?不确定,但认为它与普通集合类似——因此O(aM+bN)(a和b取决于xor和VAL之间的重叠)平均为O(MN)。实际上,在python中实现有序集可能会减慢速度。有关可能更有效的算法,请参见编辑。再次编辑一些性能测试。
def order_by4(vals, xor):
""" Order list a by each item's position in list xor, if it is found in xor,
otherwise by its position in list vals """
d = {k: False for k in xor}
for k in vals:
d[k] = True
return [k for k, v in d.items() if v]
import random
import string
import timeit
def random_phrase():
return "".join(random.choices(string.ascii_letters, k=10))
def generate_lists(M, N, overlap):
a = [random_phrase() for _ in range(M)]
b = ([random_phrase() for _ in range(N - overlap)] +
random.sample(a, k=overlap))
random.shuffle(b)
return a, b
def dreamcrash(vals, xor):
return [v for v in xor if v in vals] + [v for v in vals if v not in xor]
def schwobaseggl(vals, xor):
order = {n: i for i, n in enumerate(xor)}
len_xor = len(xor) # saves some time when sorting
return sorted(vals, key=lambda x: order.get(x, len_xor))
vals, xor = generate_lists(800000, 300000, overlap=150000) # this takes a while
for f in [dreamcrash, order_by1, order_by2, order_by3, order_by4, schwobaseggl]:
print(f, end='...')
print(timeit.timeit(stmt=f"{f.__name__}(vals, xor)", number=1, globals=globals()))
vals.sort(key=set(xor).__contains__, reverse=True)