ファロは配列をシャッフルする


31

A ファロshuffleが頻繁に「シャッフル」デッキにマジシャンで使用される技術です。ファロシャッフルを実行するには、まずデッキを2つの等しい半分にカットしてから、2つの半分をインターリーブします。例えば

[1 2 3 4 5 6 7 8]

シャローファロは

[1 5 2 6 3 7 4 8]

これは何回でも繰り返すことができます。興味深いことに、これを十分な回数繰り返すと、常に元の配列に戻ります。例えば:

[1 2 3 4 5 6 7 8]
[1 5 2 6 3 7 4 8]
[1 3 5 7 2 4 6 8]
[1 2 3 4 5 6 7 8]

1が下部に、8が上部にあることに注意してください。それがこれをアウターシャッフルにします。これは重要な違いです。

チャレンジ

整数配列A、および数値Nを指定するとNファロがシャッフルされた後に配列が出力されます。は繰り返し要素または負の要素が含まれる場合がありますが、要素の数は常に偶数になります。配列が空でないと仮定できます。Nは負の整数であると仮定することもできますが、0の場合もあります。これらの入力は、合理的な方法で取得できます。バイト単位の最短回答が勝ちです!

テストIO:

#N, A,                                              Output
1,  [1, 2, 3, 4, 5, 6, 7, 8]                        [1, 5, 2, 6, 3, 7, 4, 8]
2,  [1, 2, 3, 4, 5, 6, 7, 8]                        [1, 3, 5, 7, 2, 4, 6, 8]
7,  [-23, -37, 52, 0, -6, -7, -8, 89]               [-23, -6, -37, -7, 52, -8, 0, 89]
0,  [4, 8, 15, 16, 23, 42]                          [4, 8, 15, 16, 23, 42]
11, [10, 11, 8, 15, 13, 13, 19, 3, 7, 3, 15, 19]    [10, 19, 11, 3, 8, 7, 15, 3, 13, 15, 13, 19]

そして、大規模なテストケース:

23, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]

出力する必要があります:

[1, 30, 59, 88, 18, 47, 76, 6, 35, 64, 93, 23, 52, 81, 11, 40, 69, 98, 28, 57, 86, 16, 45, 74, 4, 33, 62, 91, 21, 50, 79, 9, 38, 67, 96, 26, 55, 84, 14, 43, 72, 2, 31, 60, 89, 19, 48, 77, 7, 36, 65, 94, 24, 53, 82, 12, 41, 70, 99, 29, 58, 87, 17, 46, 75, 5, 34, 63, 92, 22, 51, 80, 10, 39, 68, 97, 27, 56, 85, 15, 44, 73, 3, 32, 61, 90, 20, 49, 78, 8, 37, 66, 95, 25, 54, 83, 13, 42, 71, 100]  

配列にゼロ要素を含めることができますか?
リーキー修道女

@LeakyNunいいえ、ゼロ要素を処理する必要はありません。
DJMcMayhem



1
有限集合の順列は、十分な回数繰り返されると、開始した場所に戻ります。これはファロシャッフルにとって特別なことではありません。
グレッグマーティン

回答:



19

vim、62 59 54

qrma50%mb:norm@q<cr>ggqOjdd'apjma'b@q<esc>0"qDJ<C-a>D@"i@r<esc>xxdd@"

ワオ。これはおそらくPPCGのために書いた中で最もハッキングなことであり、それは何かを言っています。

入力は、最初の行でNとして、その後にそれぞれ独自の行で配列の要素が続きます。

qr         first, we're going to record the contents of the @r macro. this is
             the macro which does the faro-shuffle operation.
  ma       set the mark 'a at the beginning of the file
  50%      move to the 50% point of the file (i.e. halfway down)
  mb       set another mark here
  :norm@q  evaluate the recursive macro @q. we'll get to what that does later,
             but the interesting part here is that it's :norm@q instead of @q.
             this is because a recursive macro terminates at the end of the
             file, which means when @q terminates, @r would also abort, which
             would make calling it with a count impossible. running @q under
             :norm prevents this.
  gg       move back to the top of the file for the next iteration
q          end recording
O          now we're inserting contents of the @q macro, the recursive part
             we can't record it directly because it's destructive
  j        move to line directly below mark 'b (which was just set before @q)
  dd       delete this line and bring it...
  'ap      up after mark 'a (which starts on line 1, bringing the N/2th line
             directly below line 1, aka line 2)
  jma      replace mark 'a one line below this so that the next time we call
             'ap, the line from the second half is interleaved with the lines
             from the first half
  'b       jump back to mark 'b (remember, 'b is the last line of the first
             half of the file, originally reached via 50%)
  @q       call ourselves, causing the macro to run until hitting EOF
0"qD       delete this into register "q
J          delete the empty line that remains
<C-a>      here's another interesting bit: we want to run @r N times. but 0@r
             means "go to column 0, and then run @r once." so we have to
             increment the input number...
D@"        and then *that* many times...
  i@r        insert @r...
xx         ... and finally, delete two characters, which is the extra @r from
             the increment
dd         delete the sequence of @rs into the "" register...
@"         and run it!

この回答を書いているときに、実際にいくつかのvimバグを見つけた可能性があります。

  • マクロを記録することは、他のマクロ内(テキストを手動で設定する場合、ではなくq)または:*maps 内ではできません。

  • :let @a='<C-v><cr>'<cr>i<C-r>a 不可解な理由のために、1つではなく2つの改行を出力します。

これらについては後で調査する可能性があります。

3バイトのDr Green EggsとHam DJに感謝します!


4
これは美しくて恐ろしいことです。私はおそらくvimでこれを行うのに十分な忍耐を持っていません。:Pまた、あなたが行うことで2つのバイトを脱ぐことができます"rck代わりにvgg"rc、あなたが行うことで、別の5をオフにすることができますdw@"i@r<esc>代わりにAA@R<C-v><esc><esc>0D@"
DJMcMayhem

@DrGreenEg​​gsandHamDJ後続の改行も取得するため、最初のものはできませんが、2番目の最適化は機能します。ありがとう!
ドアノブ

7

Python 2、59バイト

def f(n,L):exec"l=len(L)/2;L=(L+L[1:]*~-l)[::l];"*n;print L

他のPythonの回答よりもわずかに長い別のアプローチ。正の偶数の要素に対してのみ機能します。

例えば1, [1,2,3,4,5,6,7,8]、のために、配列を取りlen(L)/2-1、最初の要素を引いたそれ自身のコピーを追加します、例えば

[1,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8]

次に、すべてのlen(L)/2th要素を取得します。

[1,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8,2,3,4,5,6,7,8]
 ^       ^       ^       ^       ^       ^       ^       ^

6

Python、68 57バイト

f=lambda n,x:n and f(n-1,sum(zip(x,x[len(x)/2:]),()))or x

11バイトのゴルフをしてくれた@ Sp3000に感謝します!

Ideoneでテストします。


6

Haskell、62バイト

0!a=a
n!a|s<-length a=(n-1)![a!!mod(div(s*i+i)2)s|i<-[0..s-1]]

レッツS = 2・tは、リストのサイズです。新しいリストのi番目の要素は、enter image description here古いリストの0番目の要素、ゼロインデックス、モジュロsを取得することによって取得されます。

証明:i = 2・kが偶数の場合、

                                         enter image description here

そしてもし、I = 2・K + 1は、次に、奇数であります

                        enter image description here

したがって、インデックス付けに使用される値は、0、t、1、t + 1、2、t + 2、…です。


5

J-12バイト

副詞(!)は、左側でシャッフルの数を取り、右側でシャッフルする配列を取ります。

/:#/:@$0,#^:

Jパーサーには暗黙の副詞を記述するためのルールがありますが、優先順位は非常に低くなっています。一連の動詞を左引数として使用する場合は、必要な括弧のセットを省略できます。したがって、上記は実際にはの略で(/:#/:@$0,#)^:、左側のシャッフルの数を副詞として受け取り、次に配列を右側のシャッフルする単項関数になります。

とはいえ、次のようにシャッフルします。#は配列の長さであるため0,#、2つの要素のリストもあります。0の後にゼロ以外のものが続きます。次に#/:@$、それを入力配列の限りリストに複製し、そのソートベクトルを取得します。

リストの並べ替えベクトルは、リストを並べ替える方法に関する情報です。最小要素の(0から始まる)invdex、次に小さい要素のインデックスなどが続きます。たとえば、のソートベクトル0 1 0 1 ...はこのようになります0 2 4 ... 1 3 5 ...

Jがこのソートベクトルをソートする場合、ファロシャッフルします。しかし、私たちが0 1 2 3 ...戻ってくるので、それは些細なことです。そのため、dyadic/:を使用して、入力配列をあたかも 0 2 4 ... 1 3 5 ... Faroシャッフルするかのようにソートします。

以下の使用例。tryj.tkで試してみてください!

   1 (/:#/:@$0,#^:) 1 2 3 4 5 6 7 8
1 5 2 6 3 7 4 8

   f =: /:#/:@$0,#^:

   2  f  1 2 3 4 5 6 7 8
1 3 5 7 2 4 6 8

   7  f  _23 _37 52 0 _6 _7 _8 89   NB. "negative 1" is spelled _1
_23 _6 _37 _7 52 _8 0 89

   1  f  0 0 0 0 1 1 1              NB. odd-length lists
0 1 0 1 0 1 0

5

Pyth- 8 7バイト

@issacgのおかげで1バイト節約

usCc2GE

こちらからオンラインでお試しください


2
うーん... PythがJellyを倒した場合、Jellyの回答に何か問題があるはずです。
リーキー修道女

2
入力順序を交換し、を削除しQてバイトを保存します。JellyがPythを破った場合、Pythの回答に何か問題があるはずです。:)
isaacg

@isaacgくそー、前に試したことがあると誓ったかもしれない。なぜそれが機能するのですか?そのデフォルトにフックするべきではありませんuなしで固定小数点をか?
マルティセン

@Maltysenそうですね、私が試した1つのテストケースでしか動作しなかったと思います。ごめんなさい
isaacg

@LeakyNunありがとう @Dennis@issacg、Pyth及びゼリーは現在(7バイト)に等しいです。; D
ケビンクルーッセン


2

JavaScript(ES6)、 61 51バイト

(n,a)=>[...a].map((e,i)=>a[(i<<n)%~-a.length||i]=e)

入力配列を所定の位置に変更し、元の配列のコピーを返します。これが受け入れられない場合&&a、変更された配列を返すために接尾辞を付けることができます。nJavaScriptの整数演算の制限により、小さな値に対してのみ機能します。61n @Lynnの式に基づいて、larger で動作する60バイトの再帰バージョン:

f=(n,a,l=a.length)=>n?f(n-1,a.map((_,i)=>a[(i*-~l>>1)%l])):a

2

MATL、11バイト

w:"tn2/e!1e

訂正してくれた@Dennisに感謝

オンラインでお試しください!

説明

w         % Take the two inputs N and A. Swap them
:         % Generate [1 2 ... N]
"         % Repeat N times
  tn2/    %   Duplicate A. Number of elements divided by 2
  e       %   Reshape to that number of rows
  !       %   Transpose
  1e      %   Reshape to one row
          % End (implicit)
          % Display (implicit)

なぜw必要なのですか?
デビッド

@Davidそれが修正でした。それなしでは、N = 0の場合、ループは入力されず、2番目の入力は取得されません
ルイスメンドー

ああ、迷惑です!
デビッド

2

J、22 19 17バイト

@Garethのおかげで 3バイト。

@algorithmsharkのおかげで2バイト。

-:@#({.,@,.}.)]^:

使用法

>> f =: -:@#({.,@,.}.)]^:
>> 2 f 1 2 3 4 5 6 7 8
<< 1 3 5 7 2 4 6 8

>>STDINと<<STDOUT はどこにあります。

以前の22バイトバージョン:

({~[:,/@|:@i.2,-:@#)^:

使用法

>> f =: ({~[:,/@|:@i.2,-:@#)^:
>> 2 f 1 2 3 4 5 6 7 8
<< 1 3 5 7 2 4 6 8

>>STDINと<<STDOUT はどこにあります。


Jの解析規則のため、2文字の外側の括弧を削除できます。
algorithmshark

18バイトの転置インデックス{~2,@|:@i.@,-:@#^:を使用する代替。
マイル

使用する別の方法として17のバイトを[:,@|:]]\~_2%~#^:
マイル

@miles私は,@|:@$~2,-:@#^:15バイトで動作すると信じています
ジョナ

1

Mathematica 44バイト

@milesのおかげで4バイト節約されました。

Riffle@@TakeDrop[#,Length@#/2]&~Nest~##&

Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[list, nShuffles]リストを2つの等しいサブリストに分割し、シャッフル(Riffles)します。


 Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[Range@8, 1]

{1、5、2、6、3、7、4、8}


Riffle @@ TakeDrop[#, Length@#/2] &~Nest~## &[Range@100, 23]

{1、30、59、88、18、47、76、6、35、64、93、23、52、81、11、40、69、98、28、57、86、16、45、74、4 、33、62、91、21、50、79、9、38、67、96、26、55、84、14、43、72、2、31、60、89、19、48、77、7、36 、65、94、24、53、82、12、41、70、99、29、58、87、17、46、75、5、34、63、92、22、51、80、10、39、68 、97、27、56、85、15、44、73、3、32、61、90、20、49、78、8、37、66、95、25、54、83、13、42、71、100 }


を使用すると、解析するシーケンスをに対する追加の引数として取得しながら、40バイトTakeDrop使用したソリューションを見つけることができます。Riffle@@TakeDrop[#,Length@#/2]&~Nest~##&##Nest
マイル

@マイル。とてもいい使い方TakeDrop。そして##、シーケンスの挿入に使用することをお勧めします。
DavidC

1

APL、 23 21文字

({⊃,/⍵(↑,¨↓)⍨2÷⍨⍴⍵}⍣N)A

仮定なし(デニスに感謝)と1文字短縮:

({{∊,⌿2(2÷⍨≢⍵)⍴⍵}⍣⎕)⎕

オンラインで試してみてください。


1

java、109バイト

int[]f(int[]a,int n){for(int x,q=a.length,d[];0<n--;a=d){d=new int[q];for(x=0;x<q;x++)d[(2*x+2*x/q)%q]=a[x];}return a;}

説明:要素がファロシャッフルされたときの要素の動きにはパターンがあります。

xを元のインデックスとする

yを新しいインデックスとする

Lを配列の長さとする

  • yはdouble x
  • xがLの半分以上の場合、yをインクリメントします
  • 配列の境界内にyを保持します

またはコードとして: y=(2*x+x/(L/2))%L

これは、インデックスが0から始まることを前提としています。さらに詳しく説明するコードを次に示します。

int[] faroShuffle( int[] array, int numberOfShuffles ) {
    //repeat the faro shuffle n times
    for( int index, length=array.length, destination[]; 0<numberOfShuffles--; array=destination ) {
        //new array to copy over the elements
        destination=new int[length];
        //copy the elements into the new array
        for( index=0; index<length; index++ )
            destination[(2*index+2*index/length)%length]=array[index];
        //at the end of each loop, copy the reference to the new array and use it going forward
    }
    return array;
}  

テストケースについてはideoneをご覧ください


1年以上経っていることは知っていますが、ゴルフのいくつかの部分をゴルフにかけることができます:void f(int[]a,int n){for(int x,q=a.length,d[];0<n--;a=d)for(d=new int[q],x=0;x<q;)d[(2*x+2*x/q)%q]=a[x++];}107バイト -現在の答えは109ではなく119なので、-12バイトです)。入力配列を変更するので、それを返す必要はないので、バイトを減らすためにvoidに変更できます。ああ、カリー化してJava 8ラムダに変換すると、さらに短くすることができます:a->n->{for(int x,q=a.length,d[];0<n--;a=d){d=new int[q];for(x=0;x<q;x++)d[(2*x+2*x/q)%q]=a[x];}}96バイト
ケビンクルーイッセン

1

ジュリア、 45 42バイト

a\n=n>0?reshape(a,endof(a)÷2,2)'[:]\~-n:a

オンラインでお試しください!

使い方

\このタスクの二項演算子を(再)定義します。ましょう配列にすることと、 N負でない整数。

nが正の場合、配列をシャッフルします。これは、長さ(a)÷22列の行列に再形成することで実現されます。'結果の行列を転置し、2行を作成してから、結果を次のように平坦化します。[:]ます。Juliaは行列を列優先の順序で格納するため、2つの行がインターリーブされます。

その後、\シャッフルされたaおよびn-1~-n)を引数として再帰的に呼び出し、追加のシャッフルを実行します。一度Nに達する0、我々は現在の値を返します。



0

実際には、15バイト

`;l½≈@│t)HZ♂i`n

オンラインでお試しください!

説明:

`;l½≈@│t)HZ♂i`n
`            `n  do the following n times:
 ;l½≈              push half the length of the array
     @             swap
      │            duplicate entire stack
       t)H         last L//2 elements, first L//2 elements
          Z♂i      zip, flatten each element

0

プロローグ、116バイト

a([],[[],[]]).
a([H,I|T],[[H|U],[I|V]]):-a(T,[U,V]).
f(X,0,X).
f(X,N,Y):-N>0,M is N-1,f(X,M,Z),a(Z,[A,B]),append(A,B,Y).

使用法

?- f([1,2,3,4,5,6,7,8],2,X).
X = [1, 5, 2, 6, 3, 7, 4, 8] ;
false.


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.