具有重复连续数字的范围

Posted

技术标签:

【中文标题】具有重复连续数字的范围【英文标题】:Range with repeated consecutive numbers 【发布时间】:2018-06-12 09:19:40 【问题描述】:

我想创建一个数字范围(例如 (1, 5)),其中包含一些重复(例如 4):

[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]

一种方法是写:

list(itertools.chain(*([x] * 4 for x in range(1, 5))))

或类似:

list(itertools.chain(*(itertools.repeat(x, 4) for x in range(1, 5))))

但是,有一个平坦的步骤,可以避免。

有没有更pythonic或更紧凑的版本来生成这样的序列?

【问题讨论】:

如果你不考虑订单,你可以试试这个,print range(1,5)*4。或者试试这个,sorted(range(1,5)*4) @MohamedThasinah,感谢您的意见 - 不幸的是,订单与我的情况相关。 【参考方案1】:

您可以只使用 列表推导

l = [i for i in range(1, 5) for _ in range(4)]

输出

[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]

【讨论】:

【参考方案2】:

您的解决方案没有问题。但是您可以使用chain.from_iterable 来避免解包步骤。

否则,我唯一的其他建议是 NumPy,如果您愿意使用 3rd 方库。

from itertools import chain, repeat
import numpy as np

# list solution
res = list(chain.from_iterable(repeat(i, 4) for i in range(1, 5)))

# NumPy solution
arr = np.repeat(np.arange(1, 5), 4)

【讨论】:

@jpp- 基于 numpy 的解决方案的好答案。【参考方案3】:

试试这个,

range(1,5)*4 # if you don't consider order
sorted(range(1,5)*4) # for ordered seq

性能更新

Mihai Alexandru-Ionut 答案:

%timeit [i for i in range(1, 5) for _ in range(4)]

1000000 loops, best of 3: 1.91 µs per loop

jpp 答案:

%timeit list(chain.from_iterable(repeat(i, 4) for i in range(1, 5)))

100000 loops, best of 3: 2.12 µs per loop

%timeit np.repeat(np.arange(1, 5), 4)

1000000 loops, best of 3: 1.68 µs per loop

罗里道尔顿回答:

%timeit [n for n in range(1,5) for repeat in range(4)]

1000000 loops, best of 3: 1.9 µs per loop

jedwards 回答:

%timeit list(i//4 for i in range(1*4, 5*4))

100000 loops, best of 3: 2.47 µs per loop

RoadRunner 建议在评论区:

%timeit for i in range(1, 5): lst.extend([i] * 4)

1000000 loops, best of 3: 1.46 µs per loop

我的回答:

%timeit sorted(range(1,5)*4)

1000000 loops, best of 3: 1.3 µs per loop

【讨论】:

使用 Python 3,这将是:sorted(list(range(1, 5)) * 4)。无论如何,不​​错的 hack - 还没想过那个。 @miku 但排序不会增加不必要的时间复杂度吗? 在展平之上,您还添加了n log(n) 排序。 从提出的解决方案来看,我认为这是最快的 公平地说,@jpp 使用 numpy 的答案对于长数组来说是最快的。使用纯 python 这个答案对于这个例子和长数组都是最好的【参考方案4】:

我认为chain + repeat 可能是你最好的选择。话虽如此,

start = 1
stop = 5
repeat = 4

x = list(i//repeat for i in range(start*repeat, stop*repeat))

print(x)

应该有效(至少对于正参数)。

【讨论】:

【参考方案5】:

我非常喜欢简单易懂的代码。有了这个理念,我会使用

[n for n in range(1,5) for repeat in range(4)]

【讨论】:

【参考方案6】:

我只是想提一下,extend 也可能是一个选项。也许不如单行列表理解那么漂亮,但是当buckets 的大小增加时它会表现得更好

def listExtend():
    a = []
    for i in range(1,5):
        a.extend([i]*4)
    return a


def listComprehension():
    return [[i,x] for i in range(1, 5) for x in range(4)]


import timeit
print(timeit.timeit(stmt="listComprehension()", setup="from __main__ import listComprehension", number=10**7))
print(timeit.timeit(stmt="listExtend()", setup="from __main__ import listExtend", number=10**7))
14.2532608
8.78004566

【讨论】:

【参考方案7】:

一个选项,虽然它需要安装一个包,是itertation_utilities.replicate

>>> from iteration_utilities import replicate
>>> list(replicate(range(1, 5), 4))
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]

如果您不想安装该软件包,replicate 功能本质上等同于此功能:

from itertools import repeat

def replicate(items, repeats):
    for item in items:
        for _ in repeat(None, repeats):
            yield item

以防万一您对性能感兴趣,我为几个(不是全部)建议的替代方案做了一些微基准测试:

如您所见,NumPy 和 iteration_utilities 方法是 最快,而所有其他方法的速度大致相同。

有趣的是,在这些其他方法中,list.extend 方法最快,而(我的)自定义生成器最慢。我没想到。

这里是复制基准的代码:

from iteration_utilities import replicate
from itertools import chain, repeat
import numpy as np

def replicate_generator_impl(upper):
    for item in range(1, upper):
        for _ in repeat(None, 4):
            yield item

def replicate_generator(upper):
    return list(replicate_generator_impl(upper))

def iteration_utilities_replicate(upper):
    return list(replicate(range(1, upper), 4))

def double_comprehension(upper):
    return [i for i in range(1, upper) for _ in range(4)]

def itertools_chain(upper):
    return list(chain(*([x] * 4 for x in range(1, upper))))

def itertools_chain_from_iterable(upper):
    return list(chain.from_iterable(repeat(i, 4) for i in range(1, upper)))

def extend(upper):
    a = []
    for i in range(1, upper):
        a.extend([i] * 4)
    return a

def numpy_repeat(upper):
    return np.repeat(np.arange(1, upper), 4)

from simple_benchmark import benchmark

funcs = [replicate_generator, iteration_utilities_replicate, double_comprehension, itertools_chain, itertools_chain_from_iterable, extend, numpy_repeat]
arguments = 2**i: 2**i for i in range(1, 15)
b = benchmark(funcs, arguments, argument_name='size')
b.plot()

如果您想知道如果没有 NumPy 方法会是什么样子:


免责声明:我是iteration_utilitiessimple_benchmark 的作者。

【讨论】:

以上是关于具有重复连续数字的范围的主要内容,如果未能解决你的问题,请参考以下文章

使用 sqlite 查找连续重复的数量

最长连续不重复子序列

通过重复固定范围的值来扩展列表

二十:数字重复长度计算

MySQL连续出现的数字

MySQL连续出现的数字