翻转列表中的每个第二对

时间:2018-03-29 02:40:37

标签: python

将随机数列表分成两组的最快方法是什么,交替翻转每一对?例如:

pleatedTuple=(0, 1, 3, 2, 4, 5, 7, 6, 8, 9)

在一次操作中我想要的是什么:

flatPairs=[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

项目将是随机的单个数字,我只是为了可读性而使它们连续。我需要在运行中完成数千个这样的速度,因此速度优先。 Python 3.6.4。

感谢您的任何想法,我对此感到难过。

6 个答案:

答案 0 :(得分:5)

选项1
只要这是我们正在谈论的,让我们尝试列表理解:

flatPairs = [
    [x, y] if i % 2 == 0 else [y, x] for i, (x, y) in enumerate(
        zip(pleatedTuple[::2], pleatedTuple[1::2])
    )
]

您也可以使用循环从头开始构建:

flatPairs = []
for i, (x, y) in enumerate(zip(pleatedTuple[::2], pleatedTuple[1::2])):
    if i % 2 == 0:
        flatPairs.append([x, y])
    else:
        flatPairs.append([y, x])

print(flatPairs)
[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

选项2
使用Ned Batchelder的chunking subroutine chunks并翻转每个替代子列表:

# https://stackoverflow.com/a/312464/4909087
def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]

调用chunks并耗尽返回的生成器以获取对列表:

flatPairs = list(chunks(pleatedTuple, n=2))

现在,用循环反转所有其他对。

for i in range(1, len(flatPairs), 2):
    flatPairs[i] = flatPairs[i][::-1]

print(flatPairs)
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]

请注意,在这种情况下,结果是元组的列表。

<强>性能
(仅限我的答案)
我对表演很感兴趣,所以我决定给出答案:

# Setup
pleatedTuple = tuple(range(100000))    

# List comp
21.1 ms ± 1.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)    
# Loop
20.8 ms ± 1.71 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# chunks
26 ms ± 2.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

为了获得更高的性能,您可以使用性能更高的替代方案替换chunks生成器:

flatPairs = list(zip(pleatedTuple[::2], pleatedTuple[1::2]))

然后根据需要使用循环反转。这大大缩短了时间:

13.1 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

加速2倍,p!但要注意,这并不像发电机那样具有内存效率......

答案 1 :(得分:2)

您可以将iter与列表切片结合使用:

pleatedTuple=(0, 1, 3, 2, 4, 5, 7, 6, 8, 9)
new_data = [list(pleatedTuple[i:i+2][::-1]) if c%2 != 0 else list(pleatedTuple[i:i+2]) for i, c in zip(range(0, len(pleatedTuple), 2), range(len(pleatedTuple)))]

输出:

[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

答案 2 :(得分:2)

您可以使用标准分组习惯用法并将其压缩为长度:

>>> by_pairs_index = zip(range(len(pleatedTuple)), *[iter(pleatedTuple)]*2)
>>> [[b, a] if i%2 else [a,b] for i,a,b in by_pairs_index]
[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

如果表现至关重要,您可以考虑其他方法。

答案 3 :(得分:2)

选项1

使用mapreversed以及切片分配。

p = list(map(list, zip(pleatedTuple[::2], pleatedTuple[1::2])))
p[1::2] = map(list, map(reversed, p[1::2]))

p

[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

轻微变化

p = list(map(list, zip(pleatedTuple[::2], pleatedTuple[1::2])))
p[1::2] = (x[::-1] for x in p[1::2])

p

[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

选项2

def weird(p):
    return [[p[2 * i + i % 2], p[2 * i + (i + 1) % 2]] for i in range(len(p) // 2)]

weird(pleatedTuple)

[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

更通用

def weird(p, k):
    return [list(p[i*k:(i+1)*k][::(i-1)%2*2-1]) for i in range(len(p) // k)]

weird(pleatedTuple, 2)

[[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]
weird(pleatedTuple * 3, 3)

[[0, 1, 3],
 [5, 4, 2],
 [7, 6, 8],
 [1, 0, 9],
 [3, 2, 4],
 [6, 7, 5],
 [8, 9, 0],
 [2, 3, 1],
 [4, 5, 7],
 [9, 8, 6]]

答案 4 :(得分:1)

您可以在numpy中执行此操作:

>>> pleatedTuple=(0, 1, 3, 2, 4, 5, 7, 6, 8, 9)
>>> pleatedArray = np.array(pleatedTuple)
>>> flat2D = pleatedArray.reshape(5,2)
>>> flat2D[1::2] = np.flip(pleated2D[1::2], axis=1)

当然,这可能会浪费在元组和数组之间转换的时间,因为它节省了在numpy而不是Python中进行微小循环。 (从快速测试来看,它在示例大小上花费的时间大约是Coldspeed's Option 2的两倍,并且在你得到更多,更长的元组之前不会赶上,并且你有一堆小元组,而不是几个巨人。)

但是如果你关注速度,那么显而易见的事情就是将所有这些成千上万的褶皱元组放入一个巨大的numpy数组中并一次完成它们,然后它可能会快得多。 (尽管如此,我们可能正在谈论为数以千计的这些节省毫秒数。)

答案 5 :(得分:-1)

我使用的是:

pleatedTuple=(0, 1, 3, 2, 4, 5, 7, 6, 8, 9)


for i in range(0,len(pleatedTuple),2):
      print(pleatedTuple[i:i+2])

这是你在找什么?

(0, 1)
(3, 2)
(4, 5)
(7, 6)
(8, 9)