簡體   English   中英

如何在不使用循環的情況下生成循環數字序列?

[英]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而不是listnumpy數組時,我建議使用此解決方案。

首先超長它(使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM