[英]How to generate a cyclic sequence of numbers without using looping?
我想生成一個循環的數字序列,如: [ABCABC]
任意長度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
)將小於我所考慮的長度( N
)。 我知道這是一個非常新的問題,但我真的被卡住了
你可以使用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:這是使用modulus
處理通用序列以生成那些循環索引的一種方法 -
def cyclic_seq(x, N):
return np.take(x, np.mod(np.arange(N),len(x)))
方法#2:為了提高性能,這里有另一種方法,它將最大間隔數的多個slicing
,然后利用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
似乎運作良好。
你可以使用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的基准測試中所看到的 ,與其他答案相比,這種方法在速度方面通常是中等的。 當你希望迭代器return
ed而不是list
或numpy
數組時,我建議使用此解決方案。
首先超長它(使用math.ceil
)然后在tile
之后resize
它的resize
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
自動在1D中平鋪響應
您可以使用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
編輯:如果你想用out循環實現它,你將需要遞歸函數。 基於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)
...:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.