8/25追記
最終版??
http://qiita.com/ttatsf/items/d4543ccc80e0fbe3891d#comment-3eccf9c112d73c505bc2
8/23追記
下記のプログラムだと全てのshuffleパターンが網羅されていない,という指摘がありました.
[0,1,2,3] → [1,0,3,2] のような奇遇交換の例.
利用にあたってはご注意ください.
8/21追記
最終的に2行になった模様(白目)
def shuffle_all_move(items):
rand_ord = random.sample(range(len(items)), k=len(items))
return [items[r] for i, r in sorted(zip(rand_ord, rand_ord[1:]+rand_ord[:1]))]
実行速度も僅かに上のコードの方がわずかに速いようです(コメント欄に計測結果を載せています)
8/19追記
コメント欄にある,ttatsfさんが作ってくださったものが一番気に入っています.
(ベースにある「サットロのアルゴリズム」は7of9さんに紹介頂きました)
他にもコメントでコードを書いてくださった皆様,ありがとうございました.
import random
def shuffle_all_move( items ):
length = len( items )
res = [ 0 ] * length
rand_ord = random.sample( range( length ), k=length )
for i in range( length ) :
res[ rand_ord[ i ] ] = items[ rand_ord[ ( i + 1 ) % length ] ]
return res
実にエレガント!
…というわけで,下の適当なDIY shuffleより上記を利用することをおススメしたいw
元の投稿
絶対に要素が移動するようなshuffleのpython+numpy実装です(配列の要素が3以上であることを仮定しているので注意).
手順
- ランダムに要素を3グループに分割
- グループ毎にshuffle
- グループを1つスライドさせる.
1のランダムなグループ分割は,実際にはshuffleしてから配列を3つに分割することで実現.shuffleされた配列のグループをスライドさせても,元の配列の位置とは無関係になってしまうので,後でこのshuffleを元に戻す.これにより,元の配列と必ず違う位置に移動することが保障される.
このコードでは,下記の2つのページにあるコードを借用しています.
※ resettable_shuffle/reset_shuffle
http://qiita.com/EafT/items/9527cb30409b70106fd4
※ divide_list
http://fits.hatenablog.com/entry/2015/11/09/211012
def shuffle_all_move(_array):
array = _array.copy()
seed = random.randint(0,np.iinfo(np.int32).max)
resettable_shuffle(array,seed)
array = divide_list(array,3)
if type(array[0]) == list:
array = array[-1] + array[0] + array[1]
else:
array = np.vstack((array[-1], array[0],array[1]))
return reset_shuffle(array,seed)
実行例
test_array = ['a','b','c','d','e','f']
print(test_array)
test_array = shuffle_all_move(test_array)
print(test_array)
['a', 'b', 'c', 'd', 'e', 'f']
['c', 'e', 'f', 'b', 'd', 'a']