2017-04-10 115 views
4

我想生成相同的编号的循环序列:[A B C A B C]任意长度N我想:如何在不使用循环的情况下生成循环数字序列?

import numpy as np 
def cyclic(N): 
    x = np.array([1.0,2.0,3.0]) # The main sequence 
    y = np.tile(x,N//3) # Repeats the sequence N//3 times 
    return y 

,但我的代码的问题是,如果我三个输入任意一个整数是不是整除,则结果会有比我想象的更小的长度(N)。我知道这是很newbish问题,但我真的卡住了

+0

这是否总是一个1d数组? –

+0

@WillemVanOnsem是 –

+0

发布的解决方案是否适合您? – Divakar

回答

5

你可以使用numpy.resize

x = np.array([1.0, 2.0, 3.0]) 

y = np.resize(x, 13) 

y 
Out[332]: array([ 1., 2., 3., 1., 2., 3., 1., 2., 3., 1., 2., 3., 1.]) 

警告:这是答案并不延伸到2D,因为resize重复之前平展阵列。

1

您可以使用itertools.cycle,无限迭代器,对于这个:

>>> import itertools 
>>> it = itertools.cycle([1,2,3]) 
>>> next(it) 
1 
>>> next(it) 
2 
>>> next(it) 
3 
>>> next(it) 
1 

你获得序列(N)的具体长度,与itertools.islice结合起来:

>>> list(itertools.islice(itertools.cycle([1,2,3]),11)) 
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2] 

编辑:你可以在Divakar's benchmark看到,相较于其他的答案这种做法是在速度方面一般中间。我建议何时此解决方案需要迭代器return而不是listnumpy阵列。

1

首先,它后过长度它(使用math.ceil)然后resizetile

import numpy as np 
import math 
def cyclic(N): 
    x = np.array([1.0,2.0,3.0]) # The main sequence 
    y = np.tile(x, math.ceil(N/3.0)) 
    y = np.resize(y, N) 
    return y 

服用Daniel Forsman的建议之后,它可以被简化为

import numpy as np 
def cyclic(N): 
    x = np.array([1.0,2.0,3.0]) # The main sequence 
    y = np.resize(x, N) 
    return y 

因为np.resize自动平铺响应in 1D

+0

'np.resize'会在1D中自动平铺响应,所以不需要额外的步骤。 –

+0

@DanielForsman真棒,确实 – xhg

0

你可以使用itertools循环。

In [3]: from itertools import cycle 
In [4]: for x in cycle(['A','B','C']): 
...:  print(x) 
...: 
C 
A 
B 
C 
A 
B 
C 
A 
B 
C 
A 
B 
C 
A 
B 
C 
A 
B 

编辑: 如果你想出来的循环来实现它,你将需要递归函数。基于itertools循环等的解决方案只是隐藏导入函数后面的循环。

In [5]: def repeater(arr, n): 
    ...:  yield arr[0] 
    ...:  yield arr[1] 
    ...:  yield arr[2] 
    ...:  if n == 0: 
    ...:   yield StopIteration 
    ...:  else: 
    ...:   yield from repeater(arr, n-1) 
    ...: 
+0

关键是不使用任何for,if或while循环! –

+0

将'cycle'与'islice'结合起来,可以轻松创建一个长度为n的序列,正如我在我的回答中所建议的 –

+0

@MrzFarjamirad避免if语句的原因是什么,当它们只是隐藏在导入之后时。 – greole

2

方法1: Here'e一种方法使用modulus产生的循环索引来处理通用序列 -

def cyclic_seq(x, N): 
    return np.take(x, np.mod(np.arange(N),len(x))) 

方法2:出于性能,下面的砖的另一方法间隔的最大数量的多个再利用的slicing以选择第一N元素 -

def cyclic_seq_v2(x, N): 
    return np.tile(x,(N+N-1)//len(x))[:N] 

个样品试验 -

In [81]: cyclic_seq([6,9,2,1,7],14) 
Out[81]: array([6, 9, 2, 1, 7, 6, 9, 2, 1, 7, 6, 9, 2, 1]) 

In [82]: cyclic_seq_v2([6,9,2,1,7],14) 
Out[82]: array([6, 9, 2, 1, 7, 6, 9, 2, 1, 7, 6, 9, 2, 1]) 

运行测试

In [327]: x = np.random.randint(0,9,(3)) 

In [328]: %timeit np.resize(x, 10000) # @Daniel Forsman's solution 
    ...: %timeit list(itertools.islice(itertools.cycle(x),10000)) # @Chris soln 
    ...: %timeit cyclic_seq(x,10000) # Approach #1 from this post 
    ...: %timeit cyclic_seq_v2(x,10000) # Approach #2 from this post 
    ...: 
1000 loops, best of 3: 296 µs per loop 
10000 loops, best of 3: 185 µs per loop 
10000 loops, best of 3: 120 µs per loop 
10000 loops, best of 3: 28.7 µs per loop 

In [329]: x = np.random.randint(0,9,(30)) 

In [330]: %timeit np.resize(x, 10000) # @Daniel Forsman's solution 
    ...: %timeit list(itertools.islice(itertools.cycle(x),10000)) # @Chris soln 
    ...: %timeit cyclic_seq(x,10000) # Approach #1 from this post 
    ...: %timeit cyclic_seq_v2(x,10000) # Approach #2 from this post 
    ...: 
10000 loops, best of 3: 38.8 µs per loop 
10000 loops, best of 3: 101 µs per loop 
10000 loops, best of 3: 115 µs per loop 
100000 loops, best of 3: 13.2 µs per loop 

In [331]: %timeit np.resize(x, 100000) # @Daniel Forsman's solution 
    ...: %timeit list(itertools.islice(itertools.cycle(x),100000)) # @Chris soln 
    ...: %timeit cyclic_seq(x,100000) # Approach #1 from this post 
    ...: %timeit cyclic_seq_v2(x,100000) # Approach #2 from this post 
    ...: 
1000 loops, best of 3: 297 µs per loop 
1000 loops, best of 3: 942 µs per loop 
1000 loops, best of 3: 1.13 ms per loop 
10000 loops, best of 3: 88.3 µs per loop 

性能,approach #2似乎合作得非常好。

+0

我想你现在要'return np.tile(x,(N // len(x))+ 1)[:N]',例如'cyclic_seq_v2([6,9,2,1,7 ],7)'returns'array([6,9,2,1,7])' –

+0

这也是非常令人失望的,尽管这是任何人都可以使用'np.resize'的唯一可能的方式,至少快5倍。 –

+0

这个任务在'itertools'上使用'numpy'有没有好处? –

相关问题