[英]More 'Pythonic' Way to alternate list shuffle
Trying to 'shuffle' a list with even number of items. 尝试使用偶数项目“混洗”一个列表。 Splitting the list,
L
in half and alternating taking an element from each. 拆分列表,
L
成两半并交替从每个中取一个元素。
I've tried pop
, but that approach was unable to get me to a one-liner. 我试过
pop
,但这种方法无法让我进入单行。 ( while
loop) and I know there is likely some more succinct way to move through it. (
while
循环),我知道可能有一些更简洁的方式来完成它。
The shuffle
from random
isn't exactly what I need, either – because that randomizes the entire order instead of alternating between the split list. 来自
random
shuffle
也不是我所需要的 - 因为它使整个订单随机化而不是在拆分列表之间交替。
If a one-liner isn't possible, is that because it's more readable in a while
loop? 如果不能使用单行,那是因为它在
while
循环中更具可读性吗?
def shuffle(L):
'''
I apologize in advance for how wet the following code is...
Example:
>>> shuffle([1, 2, 3, 4, 5, 6])
[1, 4, 2, 5, 3, 6]
'''
return [L[:(len(L)//2)][0], L[(len(L)//2):][0], L[:(len(L)//2)][1], L[(len(L)//2):][1], L[:(len(L)//2)][2], L[(len(L)//2):][2]]
other attempt: 其他尝试:
def shuffle(L):
x, L_first, L_next, L = len(L), L[:(len(L)//2)], L[(len(L)//2):], []
while len(L) != x:
L.extend([L_first.pop(0), L_next.pop(0)])
return L
Use slice assignment with a step: 使用切片分配和步骤:
def shuffle(l):
result = [None] * len(l)
# Put the first half of l in the even indices of result
result[::2] = l[:len(l)//2]
# Put the second half of l in the odd indices of result
result[1::2] = l[len(l)//2:]
return result
If I understand correctly, you could also opt for itertools.chain.from_iterable
after zipping to get the alternating effect. 如果我理解正确,你也可以在压缩之后选择
itertools.chain.from_iterable
以获得交替效果。
from itertools import chain
def shuff(l):
return list(chain.from_iterable(zip(l[:len(l)//2], l[len(l)//2:])))
Demo 演示
>>> shuff(list(range(1, 7))
[1, 4, 2, 5, 3, 6]
One possibility (requires an external library but the recipe can also be found in the itertools
-recipes section ) is: 一种可能性(需要一个外部库,但配方也可以在
itertools
-recipes部分找到 )是:
from iteration_utilities import roundrobin
def shuffle(L):
return list(roundrobin(L[:len(L)//2], L[len(L)//2:]))
This is probably slower than list assignment but it also works for arbitary amounts of iterables without problems and it doesn't require odd-sized-input handling: 这可能比列表赋值慢,但它也适用于任意数量的迭代,没有问题,并且它不需要奇数大小的输入处理:
>>> shuffle([1, 2, 3, 4, 5, 6, 7])
[1, 4, 2, 5, 3, 6, 7]
>>> shuffle([1, 2, 3, 4, 5, 6])
[1, 4, 2, 5, 3, 6]
I did some timings and @user2357112 definetly has the fastest solution but my solution is at least on the second place (note that this graph is in log-log, that means the difference in absolute terms may seem smaller than it really is!): 我做了一些时间 ,@ user2357112 definetly有最快的解决方案,但我的解决方案至少在第二位(注意这个图是在log-log中,这意味着绝对值的差异可能看起来比它实际上小!):
Disclaimer: I'm the author of that iteration_utilities
library. 免责声明:我是
iteration_utilities
库的作者。
list comprehension with index calculation using modulo and floor division 列表理解与指数计算使用模数和地板划分
[ L[(i + (i % 2)*len(L))//2] for i in range(len(L)) ] # for case of even len(L)
still one line for the general case 对于一般情况仍然是一行
[ L[i//2 + (i % 2)*len(L)//2] for i in range(2*(len(L)//2)) ] + [L[-1]]*(len(L) % 2)
the index calc (i + (i % 2)*len(L))//2
指数calc
(i + (i % 2)*len(L))//2
can be parsed as adding 可以解析为添加
i//2
which gives 0, 0, 1, 1, 2, 2 ...
i//2
给出0, 0, 1, 1, 2, 2 ...
and 和
(i % 2)*len(L)//2
where (i % 2)
alternates 0, 1 for even/odd i
(i % 2)*len(L)//2
其中(i % 2)
对偶数/奇数i
交替0,1
0, len(L)//2, 0, len(L)//2, 0, len(L)//2 ...
sum: 和:
0, len(L)//2, 1, 1 + len(L)//2, 2, 2 + len(L)//2 ...
Found two solutions. 找到两个解决方案 First one is very unpythonic (using python 2.7)
第一个非常unpythonic(使用python 2.7)
a = [1, 2, 3, 4, 5, 6] # intial array
Method One (using string magic): 方法一(使用字符串魔法):
[int(p) for p in ' '.join([str(x) + ' ' + str(y) for x, y in zip(a[:len(a) / 2], a[len(a) / 2:])]).split(' ')]
Method Two: 方法二:
[i for Tuple in zip(a[:len(a) / 2], a[len(a) / 2:]) for i in Tuple]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.