将两个列表合并为一个列表并应用约束条件

3

我有两个列表A、B

A = [2,3,1,4,5,2,4]
B = [4,2,3,6,2,5,1]

我希望将A和B组合起来,如下所示:

C = [2,4,2,3,1,3,4,6,2,5,2,5,1,4]

规则:

  1. A[i]<=B[i],取A[i],然后取B[i]
  2. A[i]>B[i],取B[i],然后取A[i]

我可以使用如下循环来完成此操作:

C = []

for a,b in zip(A,B):
    if(a<=b):
        C.append(a)
        C.append(b)
    else:
        C.append(b)
        C.append(a)

这个实际上是有效的。我应该如何按照以下方式操作:
 C = [ [a,b if (a<=b)],[ b,a else] for a,b in zip(A,B)] # This is totally wrong

但是如何使用if-else来实现呢?
5个回答

5

您现在的做法很不错,因为非常易读......但是,如果您想要一个简洁明了的语句,我可以满足您:

>>> A = [2,3,1,4,5,2,4]
>>> B = [4,2,3,6,2,5,1]
>>> [i for sublist in [[a, b] if a < b else [b, a] for a, b in zip(A, B)] for i in sublist]
[2, 4, 2, 3, 1, 3, 4, 6, 2, 5, 2, 5, 1, 4]

注意事项:

  1. 在列表推导式中添加条件时,将 if - else 置于列表推导式中第一个变量后面。例如:['a' if i in (2, 4, 16) else 'b' for i in [1, 2, 3, 16, 24]]

  2. 构建(心理上的)嵌套列表推导式的最佳方式是考虑如何在正常循环中编写它。


C = [[a, b] if a < b else [b, a] for a, b in zip(A, B)]
for sublist in C:
    for i in sublist:
        yield i

然后,您只需展平嵌套的循环并将 yield i 移到前面,去掉 yield

for sublist in C for i in sublist yield i
|-> yield i for sublist in C for i in sublist
    |-> i for sublist in C for i in sublist

现在,你只需要使用上面的列表推导式替换C,就可以得到我发布的一行代码。

哦...非常感谢。这就是你的答案。我明白了。 - Shahriar
对于C中的子列表,对于子列表中的每个i i和i,对于C中的子列表,对于子列表中的每个i i和i - 可以同时使用吗? - Shahriar
不,[item_in_sublist for sublist in C for item_in_sublist in sublist]正确有效的语法。 - sberry

1
使用 itertools.chain.from_iterable
import itertools 
A = [2,3,1,4,5,2,4]
B = [4,2,3,6,2,5,1]  
list(itertools.chain.from_iterable(i if i[0]<=i[1] else (i[1], i[0]) for i in zip(A, B)))

或者通过将两个列表压缩 zip(A, B) 来对获取的 tuple 进行排序。

list(itertools.chain.from_iterable(sorted(i) for i in zip(A, B)))

使用List Comprehensionmapsorted查看时间差异

In [70]: %timeit list(itertools.chain.from_iterable(i if i[0]<=i[1] else (i[1], i[0]) for i in zip(A, B)))
100000 loops, best of 3: 3.49 µs per loop

In [71]: %timeit list(itertools.chain.from_iterable(sorted(i) for i in zip(A, B)))
100000 loops, best of 3: 5.81 µs per loop

In [72]: %timeit [i for sublist in [[a, b] if a < b else [b, a] for a, b in zip(A, B)] for i in sublist]
100000 loops, best of 3: 3.28 µs per loop

In [73]: %timeit list(itertools.chain.from_iterable(map(lambda x:x[1]>x[0] and (x[0],x[1]) or (x[1],x[0]),zip(A,B))))
100000 loops, best of 3: 4.26 µs per loop

我认为随着元素数量的增加,使用itertools解决方案相对于我发布的嵌套for循环解决方案性能更好。但据我回忆,需要一个相当大的数据集。尽管如此,我个人仍然更喜欢itertools解决方案。这是我最喜欢的模块之一。 - sberry
@sberry 在处理大型列表时,我们更倾向于使用 itertools,这也是我在这里使用它的原因。 - Vishnu Upadhyay
@VishnuUpadhyay,是的 - 但需要非常大才能产生任何效果。 - sberry

1
或者是这样的吗?
C = sum([[a,b] if a <= b else [b, a] for (a,b) in zip(A,B)], [])

0
>>> list(itertools.chain.from_iterable(map(lambda x:x[1]>x[0] and (x[0],x[1]) or (x[1],x[0]),zip(A,B))))
[2, 4, 2, 3, 1, 3, 4, 6, 2, 5, 2, 5, 1, 4]

我不明白,请您能否解释一下? - Shahriar

-1

你可以做到

C = [sorted([a, b]) for a, b in zip(A, B)]

并将 C 的所有元素连接起来。


这是您的结果:[[2, 4],[2, 3],[1, 3],[4, 6],[2, 5],[2, 5],[1, 4]] - Shahriar
C语言的元素必须连接在一起以生成最终结果。难道你没读完整篇文章吗? - Vinay Emani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接