今日のランダムゴルフ#1:配列のシャッフル


35

シリーズについて

ランダム性のテーマを中心に、小さなシリーズのコードゴルフチャレンジを実行します。これは基本的に9ホールの ゴルフコースですが、いくつかの質問にまたがっています。通常の質問であるかのように、個々の課題に個別に参加できます。

ただし、すべての課題にわたってリーダーボードを維持します。このシリーズは、数日ごとに投稿される9つのチャレンジ(今のところ)で実行されます。9つのチャレンジすべてに参加したすべてのユーザーは、シリーズ全体を獲得する資格があります。全体的なスコアは、各チャレンジでの最短提出の合計です(したがって、チャレンジに2回答えた場合、より良い答えだけがスコアにカウントされます)。この総合リーダーボードで28日間トップの座を保持している人がいる場合は、500 repの賞金を授与します。

このシリーズにはたくさんのアイデアが並んでいますが、将来の課題はまだはっきりしていません。何か提案があれば、関連するサンドボックスの投稿でお知らせください。

穴1:配列をシャッフルする

最初のタスクは非常に単純です。整数の空でない配列を指定して、ランダムにシャッフルします。ただし、いくつかのルールがあります。

  • すべての可能な順列は同じ確率で返される必要があります(シャッフルは均一な分布を持つ必要があります)。あなたのアルゴリズムは、上のJavaScriptでそれを実装することで、均一/公平であるかどうかをチェックすることができますウィルそれシャッフルバイアスの行列が生成されます、 -結果は彼らのビルトイン限り均一になるはずですフィッシャーイエーツまたはソート(順不同)
  • 組み込みまたはサードパーティの方法を使用して、配列をシャッフルしたり、ランダムな順列を生成したり(またはすべての順列を列挙したり)しないでください。特に、使用できる組み込みのランダム関数は、一度に1つの乱数を取得することだけです。あなたはかもしれいずれかがO(1)で乱数メソッドの実行を内蔵し、要求された間隔で完全に均一であることを前提と(数学的な意味で-あなたはここで、浮動小数点表現の詳細を無視する場合があります)。言語で一度にm個の乱数のリストを取得できる場合は、m個の数字が互いに独立しており、O(m)としてカウントする限り、この機能を使用できます。
  • 実装はO(N)の時間複雑度を超えてはなりません。ここで、Nはシャッフルされる配列のサイズです。たとえば、「乱数でソート」することはできません。
  • 配列を適切にシャッフルするか、新しい配列を作成することができます(この場合、古い配列は自由に変更できます)。

完全なプログラムまたは関数を作成し、STDIN、コマンドライン引数、関数引数またはプロンプトを介して入力を取得し、戻り値またはSTDOUT(または最も近い代替)に出力して出力を生成できます。配列を適切にシャッフルする関数を作成する場合、もちろん返す必要はありません(関数が返された後に言語で変更された配列にアクセスできる場合)。

入力および出力は、任意の便利なリストまたは文字列の形式であってもよいが、範囲内の任意の整数をサポートする必要があり-2 31 ≤X <2 31。原則として、コードは長さ2 31までの配列で動作するはずですが、これは必ずしもメモリに収まる必要はなく、妥当な時間内に完了する必要もありません。(ハードコードループなどの任意のサイズ制限を見たくありません。)

これはコードゴルフなので、最短の提出(バイト単位)が勝ちです。

リーダーボード

次のスニペットは、シリーズのすべての課題にわたってリーダーボードを生成します。

回答が表示されるようにするには、次のマークダウンテンプレートを使用して、すべての回答を見出しで開始してください。

# Language Name, N bytes

N提出物のサイズはどこですか。スコアを改善する場合、古いスコアを打つことで見出しに残すことができます。例えば:

# Ruby, <s>104</s> <s>101</s> 96 bytes

(言語は現在表示されていませんが、スニペットはそれを必要とし、解析します。将来、言語ごとのリーダーボードを追加するかもしれません。)


7
私たちが「賢い」ことを許されず、「乱数を取得する」以外のライブラリー関数を使用することができないことに失望しています。Fisher-Yatesシャッフルのさらに69の実装を見たいですか?今後のタスクでこのルールを削除することを検討してください。また、なぜ時間の複雑さに制限があるのですか?少なくともO(n ^ 2)までリラックスしてください。また、O(n!)を許可すると、誰かが特にゴルフの実装を見つける可能性があると思います。
アナトリグ

7
@anatolyg制限を削除すると、すべての回答がsortby(random)(時間制限の理由)または単に.shuffle()(組み込み制限の理由)になります。これは、Fisher-Yatesなどを実装するよりもはるかに賢くないと思いますアプローチ。
マーティンエンダー

1
適切にシャッフルする場合、関数は配列を返す必要がありますか、それとも変更するのに十分ですか?のshuffle(array)代わりに関数を記述できますnewArray=shuffle(array)か?
ジオビット

1
@Bakuriu数値が固定されていれば線形時間でソートできると主張するのは、入力サイズが固定されていればO(1)で何でもできると主張するようなものです。また、関連する制限は、固定サイズの整数ではなく、固定サイズの配列です。これは、配列サイズによって、乱数の大きさが決まるためです。とにかく、時間の複雑さの制限は、実装する一般的なアルゴリズムに対してはもちろんですが、入力サイズの制限が設定されているため、言語ですぐに使用できない場合は任意精度の整数を使用する必要はありません。
マーティンエンダー

2
Adámのソリューションは、実際には14であるにもかかわらず43319バイトになるのはなぜですか
boboquack

回答:


20

Dyalog APL、25 24バイト

最初に25文字のソリューションの場合: i{⊃a[⍺⍵]←a[⍵⍺]}¨?i←⌽⍳⍴a←⎕

                      a←⎕ ⍝ evaluated input, assign to "a"
                     ⍴a   ⍝ length
                    ⍳⍴a   ⍝ 1 2 .. length
                   ⌽⍳⍴a   ⍝ length .. 2 1
                 i←       ⍝ assign to "i"
                ?i        ⍝ random choices: (1..length)(1..length-1)..(1 2)(1)
i{            }¨?i        ⍝ for each index ⍺ and corresponding random choice ⍵
   a[⍺⍵]←a[⍵⍺]            ⍝ swap a[⍺] and a[⍵]
        ←                 ⍝ in Dyalog, assignment returns its right-hand side
  ⊃                       ⍝ first element, i.e. a[⍵]
                          ⍝ the result from {} is an array of all those a[⍵]

上記のいくつかの等価変換後:

i {}¨ ?i  ←→  i {}¨∘? i   ⍝ because A f∘g B ←→ A f g B
          ←→  {}¨∘?⍨ i    ⍝ because f⍨ B ←→ B f B

割り当てi←を取り除き、キャラクターを保存できます。

{⊃a[⍺⍵]←a[⍵⍺]}¨∘?⍨⌽⍳⍴a←⎕


3
...心。吹きました。
-danwyand

1
私は右から左に読まなければならない言語ですか?? うわー!
明るい

5
@Luminousは、数学表記でよくあることです:sin cos ln sqrt x
ngn

4
@ngnにすると、前のコメントが笑えるようになります。ハ。
明るい

5
@ronalchnようなAPLのための8ビットのエンコーディングがあり、この一又はこの他の一つは、DyalogはUnicodeの代替としてこれらのいずれかを使用していると聞きました
アナトリグ

12

80386マシンコード、44 24バイト

コードのHexdump:

60 8b fa 0f c7 f0 33 d2 f7 f1 49 8b 04 8f 87 04
97 89 04 8f 75 ed 61 c3

rdrand指示の使用を提案してくれたFUZxxlに感謝します。

ソースコードは次のとおりです(Visual Studioでコンパイルできます)。

__declspec(naked) void __fastcall shuffle(unsigned size, int array[])
{
    // fastcall convention:
    // ecx = size
    // edx = array
    _asm
    {
        pushad;             // save registers
        mov edi, edx;       // edi now points to the array

    myloop:
        rdrand eax;         // get a random number
        xor edx, edx;
        div ecx;            // edx = random index in the array

        dec ecx;            // count down
        mov eax, [edi + 4 * ecx];   // swap elements
        xchg eax, [edi + 4 * edx];  // swap elements
        mov [edi + 4 * ecx], eax;   // swap elements
        jnz myloop;

        popad;              // restore registers
        ret;
    }
}

さらに別のFisher-Yates実装。ほとんどのゴルフは、レジスターにパラメーターを渡すことで達成されました。


1
rdrandたわごとや笑いにも使用できます。
-FUZxxl

@FUZxxl私はそれを完全に忘れました!
残念なことに

9

Java、88 101

基本的なFisher-Yatesシャッフルがトリックを行います。素早く簡単に実装できるため、ここではかなり一般的に使用されると感じています。ここにはループ/割り当ての詰め込みがありますが、正直なところゴルフにはあまりありませ。本質的に短いだけです。

void t(int[]s){for(int i=s.length,t,x;i>0;t=s[x*=Math.random()],s[x]=s[i],s[i]=t)x=i--;}

いくつかの改行あり:

void t(int[]s){
    for(int i=s.length,t,x;
        i>0;
        t=s[x*=Math.random()],
        s[x]=s[i],
        s[i]=t
    )
        x=i--;
}

これにより、元の配列が変更され、シャッフルされs[]ます。テストプログラム:

public class Shuffle {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,5,6,7,8,9};
        new Shuffle().t(a);
        for(int b:a)
            System.out.print(b+" ");
    }
    void t(int[]s){for(int i=s.length,t,x;i>0;t=s[x*=Math.random()],s[x]=s[i],s[i]=t)x=i--;}
}

1
いいえ、チャレンジでは、「要求された範囲で完全に均一である」と仮定できると述べています。のリクエスト範囲のMath.random()サイズは2の累乗であるため、仕様を満たしていません。
ピーターテイラー

1
@PeterTaylor JanとGeobitsの解釈は、実際に私がルールを意図した方法です-PRNGの実際のサイクル長を心配する必要ありません
マーティンエンダー

1
@MartinBüttnerサイクルの長さはここでは問題ではありません-それはあなたのルールでカバーされています。フロートの粗さは。
ジョンドボラック

3
@TheBestOne 現在投稿されている唯一のpythonソリューションよりも1バイト短い ;)
Geobits

1
もう違います!:D
Sp3000

8

Python 2、86バイト

from random import*
def S(L):i=len(L);exec"i-=1;j=randint(0,i);L[i],L[j]=L[j],L[i];"*i

これは、Fisher-Yates shuffleの簡単な実装を使用して、配列を返さずに所定の位置にシャッフルする関数です。Pythonから乱数を取得するのは高価です...

ヒントについては、@ xnorと@colevkに感謝します。


その範囲表現はかなり面倒に見えます。確かに手動でカウントダウンする方が短いwhile i:i-=1;...ですか?
xnor

@xnorええ、そうです。ありがとう。私はこの種のものwhileよりも短い傾向があることを忘れてfor
しまい

1
Awww ...今、私のJavaの答えはこれを破っていません。私は非常に短い間非常に満足していました:(
Geobits

i=len(L)whileループの先頭にデクリメントを作成して配置することにより、さらに2バイトを節約できます。
colevk

8

J、45 44文字

これは難しいものでした。

<@({.,?@#@}.({,<^:3@[{])}.)&>/@(<"0@i.@#,<)

説明は次のとおりです。

  1. # yタリーy、内の要素の数ですy
  2. ?@# y:から1までの範囲に一様に分布する乱数(#y)-1
  3. x { y:アイテムから yインデックスにありますx
  4. (<<<x) { y:のインデックスxにあるアイテムを除くすべてのアイテムy
  5. x , y:にy 追加さxます。
  6. x ({ , <^:3@[ { ]) y:インデックスxin のアイテムy、次に他のすべてのアイテム。
  7. (?@# ({ , <^:3@[ { ]) ]) yからランダムにy、それから他のすべてのアイテム。
  8. x {. y:から取得した最初のxアイテム。y
  9. x }. y:最初のxアイテムからドロップしましたy
  10. x ({. , }.) y:最初のxアイテム採取からy、最初のxアイテムがドロップされたからy
  11. x ({. , (?@# ({ , <^:3@[ { ]) ])@}.) y:最初のxアイテム採取からy最初、xからアイテムy数7のように処理しました。
  12. x ({. , ?@#@}. ({ , <^:3@[ { ]) }.) y:1つのキャラクターを保存するために引き込まれたドロップと同じこと。
  13. u/ y: のアイテムの間にu 挿入されますy
  14. < yy 箱入り
  15. <"0 yy 箱入りの各アイテム。
  16. i. y整数から0y - 1
  17. i.@# y整数から0(#y) - 1
  18. (<"0@i.@# , <) y:から整数0(#y) - 1の各箱入り、その後y、単一のボックスに入力します。Jの配列は均一であるため、これが必要です。ボックスは、そのコンテンツの形状を隠します。
  19. x u&v y:のような(v x) u (v y)
  20. > yy opened、つまり、ボックスなし。
  21. x ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&> y ボックス化されていない引数に適用される番号12のフレーズ。
  22. ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&>/ yの 項目間に挿入された番号21のフレーズy
  23. ({. , ?@#@}. ({ , <^:3@[ { ]) }.)&>/@(<"0@i.@# , <) y番号18のフレーズの結果に適用される番号22のフレーズ、またはの項目の一様な順列y

1
すべての括弧を区別できません。そして、そのトリプルボクシング<@<@<@[も謎です...説明を待っています。:)
ランダラ

2
これが説明されると、この回答に賛成票を投じる可能性が高くなります;
ジョンドヴォルザーク

@randomraどうぞ。
FUZxxl

@JanDvorak説明は満足ですか?
-FUZxxl

素晴らしい説明!from{)のすべてのボックス化された使用について知りませんでした。そして&>/、リストを操作するトリックが本当に好きです。数回前に使用できたはずです。
-randomra

5

Pyth、25バイト

ここでテストしてください。

さらに別のFisher-Yates実装。基本的に@ Sp3000 pythonソリューションと同じです。

FNrlQ1KONJ@QN XXQN@QKKJ)Q

@Jakubeのスワッピングトリックに感謝

<implicit>    Q=input()
FNrlQ1        For N in len(Q) to 1, only goes len Q-1 because how range implemented in pyth
 KON          K = random int 0-N
 J@QN         J=Q[N]
 <space>      Suppress print
 XXQN@QKKJ    Swap K and J
)             End for
Q             Print Q

これらの2つのリストの割り当てを組み合わせることで、2バイトを保存できます: `XQN @ QK XQKJ`の代わりに` XXQN @ QKKJ`。
ジャクベ

@ジャクベ、ヒントをありがとう。リスト内の値を交換する方法があったに違いないと知っていましたが、これは本当に賢い方法です。ヒントリストに追加する必要があります。
マルティセン

4

Perl、68 56 44

他の多くのソリューションと同様に、これはFisher-Yatesアルゴリズムを使用します。

nutkiのコメントを使用して、配列インデックスの$_代わりに$iを使用して操作を実行することにより、12文字が保存されます。

44:

sub f{@_[$_,$j]=@_[$j=rand$_,--$_]for 1..@_}

56:

sub f{$i=@_;$j=int(rand$i),@_[$i,$j]=@_[$j,$i]while$i--}

これは私の最初のcodegolfです。


悪いスタートではありませんが、その@_[...]ような右辺値として使用できることは知りませんでした。さらにゴルフをすることができますsub f{@_[$_,$j]=@_[$j=rand$_,--$_]for 1..@_}
-nutki

3

C、63 61 60バイト

i,t;s(a,m)int*a;{for(;m;a[m]=t)t=a[i=rand()%m--],a[i]=a[m];}

指定された配列を所定の位置に並べ替えるフィッシャーイェーツの単純な実装です。Visual Studioコンパイラ(vs2013、他のバージョンはテストしていません)およびIntelコンパイラを使用して、コンパイルとリンクを完璧に行います。見栄えの良い関数のシグネチャはs(int array[], int length)です。PythonとRubyを打ち負かしたことに正当に感銘を受けました。

これはsrand()が呼び出され、rand()が適切に実装されていることを前提としていますが、このルールはそれを可能にしていると思います:

You may assume that any built-in random number method runs in O(1) and is perfectly uniform over the requested interval

きれいにフォーマットされたバージョン:

index, temp;
shuffle(array, length) int* array;  {
    for(;length; array[index] = temp)
        index = rand() % length--,
        temp = array[length],
        array[length] = array[index];
}

関数headerを作成すれば十分だと思いますs(a,m)*a{が、どちらもテストしたくありません。のxorように-swap を実行することもできa[i]^=a[m]^=a[i]^=a[m]ます。これにより、宣言する必要もなくなりtます。
FUZxxl

@FUZxxl xorスワップが問題を引き起こすと考えられi==mます。
ジオビット

確かに@Geobits。その可能性を逃しました。
-FUZxxl

私はそれがなぜ機能しなかったのかを理解しようとしていました...それを覚えているべきでした。またs(a,m)int*a、Visual StudioとIntelコンパイラも必要です。テストするためにgccやclangをインストールしてはいけませんが、文句を言うと思います。
pseudonym117

これはかなり印象的です。何も保存しない多くの変更を試みた後、2文字を保存する方法を見つけました。最初のスワップステートメントがになるようにスワップ順序を変更するとt=a[i]i=rand()%m--ステートメントを配列インデックスとして内部に移動できます。
Runer112

3

オクターブ、88 77バイト

function s=r(s)for(i=length(s):-1:1)t=s(x=randi(i));s(x)=s(i);s(i)=t;end;end

さらに別のFisher-Yatesの実装...通常のラインリターンとスペースを追加すれば、かなり簡単です。

function s=r(s)
  for(i=length(s):-1:1) # Counting down from i to 1
    t=s(x=randi(i));    # randi is builtin number generator for an int from 0 to i
    s(x)=s(i);
    s(i)=t;
  end
end

「終了」キーワードは、残念ながらここのゴルフスコアを本当に殺します。ちょっと、「endfor」と「endfunction」の代わりに「end」を使用できます!


1
ただ、FYI、「バイト」が本当にコードで必要されていない、それだけで必ず存在しますされ、その後、コンマの後にコンマ(、言語を分離するために)少なくとも1つの番号が含まれている、との見出しは、ちょうど最後選びます消されていない番号。ただし、そこに「バイト」が入っているのはいいことです。;)
マーティン・エンダー

1
numel代わりにを使用して1バイト節約できますlenght。ボーナスとして、プログラムは2次元配列(マトリックスとも呼ばれます)でも動作します;)
paul.oderso

2

Java 8、77

(x)->{for(int i=x.length,j,t;;t=x[j*=Math.random()],x[j]=x[i],x[i]=t)j=i--;};

int[]void を取得して返すラムダです。私の最初の試みはあまり面白くなかったので、例外をスローして終了させることにしました。

テストプログラム:

interface shuff {
    void shuff(int[] x);
}
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        shuff s = (x)->{for(int i=x.length,j,t;;t=x[j*=Math.random()],x[j]=x[i],x[i]=t)j=i--;};
        int[] x = {3, 9, 2, 93, 32, 39, 4, 5, 5, 5, 6, 0};
        try {
            s.shuff(x);
        } catch(ArrayIndexOutOfBoundsException _) {}
        for(int a:x) System.out.println(a);
    }
}

1
どこでもラムダを使用するためにデリゲートを提供する必要がある場合、ラムダを使用して関数シグネチャを記述する必要を回避するのはごまかしませんか?また...かっこを削除できませんMath.random()か?
ローリング

1
@Rawling このメタ質問に投票できます。現在、ラムダに賛成する9票、反対する0票があります。はい、括弧は削除できます。
feersum

ええと、メタ投稿とこれまでのところコンセンサスがあれば、それから発射します。(そして私に2低いゴルフスコアをお楽しみください:p)
ローリング

3
通常の場合、例外で機能が停止するのは不公平だと思いますか?
-Qwertiy

1
@Qwertiy彼自身に...あなたはそれが不公平だと思う、私はそれが素晴らしいと思う。
feersum

2

Golflua、37

Golfluaの実行方法は?

~@i=1,#X`r=M.r(i)X[i],X[r]=X[r],X[i]$

入力は変数Xのテーブルとして提供されます。テーブルは所定の位置にシャッフルされます。

使用例:

> X={0,-45,8,11,2}
> ~@i=1,#X`r=M.r(i)X[i],X[r]=X[r],X[i]$
> w(T.u(X))
-45 0 8 11 2

2

R、79バイト

f=function(x){n=length(x);for(i in 1:n){j=sample(i:n,1);x[c(i,j)]=x[c(j,i)]};x}

これは、Fisher-Yatesシャッフルの簡単な実装です。R関数sampleは、与えられたベクトルから与えられたサイズの単純なランダムサンプルを等しい確率で引き出します。ここでは、整数i、...、... から各反復でサイズ1のランダムサンプルを描画していますn。質問で述べたように、これはO(1)であると想定できるため、この実装ではすべてO(N)である必要があります。


2

Matlab、67

Fisher-Yatesも実装しています。

a=input('');n=numel(a);for i=1:n;k=randi(i);a([i,k])=a([k,i]);end;a

Matlabのrandperm機能が使えないのは残念だと思いました。しかし、いじくり回した後、私はそのソースrandpermを見て、それがどのように行われるかを見るかもしれないと思ったので、1行しかないことに驚いた:[~,p] = sort(rand(1,n))=)


2

Perl、44

sub f{($_[$x],$_)=($_,$_[$x=rand++$i])for@_}

44文字の別のperl。使用例:

@x=(1..9);f(@x);print@x

2

Mathematica、82 90 83 93バイト

注:Fisher-Yatesシャッフルのこのバリエーションは、実際にはMartinBüttnerのソリューションであり、一部のコードはalephalphaによって解析されます。s入力配列です。空想的なものは何もありませんが、時には単純なものが最もとらえどころのないものです。

f@s_:=(a=s;m=Length@a;Do[t=a[[r=RandomInteger@{1,m-1}]];a[[r]]=a[[m]]; a[[m]]=t,{n,1,m-1}];a)

Doここで使用できます。それはより短いですWhile
-alephalpha

2

ルビー、57バイト

->a{a.size.times{|i|j=rand(i+1);a[i],a[j]=a[j],a[i]};p a}

入力(ラムダ関数として):

f.([1,2,3,4,5])

出力:

[2, 1, 4, 3, 5]


2

K、31文字

f:{{l[i:x,1?x]:l@|i}'|!#l::x;l}

私が前に掲げたもの(失格になったもの)ほど短くはありません…まあ。

これは基本的なFisher-Yatesシャッフルです。これはコナメーリングリストからの多くの援助で建てられました。


2

JavaScript(ES6)、66

この関数は、配列を適切にシャッフルします。また、シャッフルされた出力ではない副産物配列も返すため、考慮しないでください。

F=a=>a.map((v,i)=>a[a[i]=a[j=0|i+Math.random()*(a.length-i)],j]=v)

2

MATL、16バイト

XH`HnYr&)XHxvHHn

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

MATLのFisher-Yates。このプログラムのほぼ3分の1は手紙に捧げられていますH、MATLのクリップボード関数に対応するにます。

基本的に、Hスタックはシャッフルされたリストを追跡しながら、入力からの未使用のアイテムを保存します。


2

ジャプト、12

rÈiMqZÄ Y}[]

それを試してみてください!

-10(約半分;)@Shaggyに感謝!

私はゴルフ言語を試してみたいと思っていましたが、Japtインタープリターには優れたドキュメントがあり、ブラウザーで物事を試す方法がありました。

以下は私が取った戦略です。

  • 空の配列で入力シードを減らします
  • 各ステップで、現在の要素を挿入するランダムなスロットを見つけます

1
Japtへようこそ、私たちと一緒にいてよかったです。これは、同じ方法を使用して9バイトで機能すると思います。ただし、RNGが十分でない場合は、代わりにこれを試してください。
シャギー

@Shaggy-ヒントをありがとう!:)私はあなたの2番目のソリューションのわずかに変更されたバージョンを使用することになりました。reduce関数の3番目のパラメーターはインデックスであるため、長さはすでにわかっています。
ダナ

1

Javascript ES6、69

a=>{m=a.length;while(m)[a[m],a[i]]=[a[i=~~(Math.random()*m--)],a[m]]}

Fisher-Yatesです。

PS:Firefoxでテスト可能


@MartinBüttner、削除:)
Qwertiy


1

ハスケル、170

import System.Random
import Data.Array.IO
s a=do(_,n)<-getBounds a;sequence$map(\i->do j<-randomRIO(i,n);p<-a%i;q<-a%j;writeArray a j p;return q)[1..n]where(%)=readArray

https://wiki.haskell.org/Random_shuffleのアルゴリズムに触発された別のFisher-Yatesソリューション。

s 署名を持つ関数です: IOArray Int a -> IO [a]


1

CJam-30

q~_,,W%{_I=I)mr:J2$=@I@tJ@t}fI

http://cjam.aditsu.net/で試してください

入力例:[10 20 30 40 50]
出力例:(きれいに印刷するためにコードの最後に3020401050a pを追加します)

コードが(関数のように)スタックから入力を取得できる場合、最初の2文字を削除してサイズを28に減らすことができます。

説明:

配列の「スワップ」演算子がないため、コードは私が期待したよりも長いです
(後で実装されます:p)

q~            read and evaluate the input (let's call the array "A")
_,,           make an array [0 1 2 ... N-1] where N is the size of A
W%            reverse the array, obtaining [N-1 ... 2 1 0]
{…}fI         for I in this array
    _I=       push A[I]
    I)mr:J    push a random number from 0 to I (inclusive) and store it in J
              stack: A, A[I], J
    2$=       get A[J]
    @I@t      set A[I] = A[J]
              stack: former A[I], A
    J@t       set A[J] = former A[I]

コメントで述べたように、これは無効だと思います。少なくとも_O(N)(O(N)ループ内)です。残念ながら、CJamでそれを回避する方法はありません。
マーティンエンダー

リストは不変オブジェクトのように処理されるため、複製は参照の複製として実装されます。tリストを変更することはできず、コピーを作成する必要があるため、実際にそれを強制終了します。
Runer112

@MartinBüttnerRuner112と同じものを投稿しようとしていました。はい、に問題がある可能性がありtます。将来のバージョンで改善したいと思います
。– aditsu

したがって、このコードは、内部言語の実装の問題のため、「文字」ではなく質問の精神に従います。
-aditsu

1

JavaScript(ES 6)、61

S=a=>(a.map((c,i)=>(a[i]=a[j=Math.random()*++i|0],a[j]=c)),a)

(Firefoxのみ)という行を追加するだけで、ここでテストできshuffle = Sます。


1

STATA、161

di _r(s)
set ob wordcount($s)
token $s
g a=0
foreach x in $s{
gl j=floor(runiform()*_n)+1
replace a=`$j' if word($s,_n)=`x'
replace a=`x' if word($s,_n)=`$j'
}
l

スペースで区切られた数値として入力を期待します。必要に応じて、ヘッダーと観測値を出力から削除できますが、そうでない場合はこれより短くなります。


これは何_nですか?
マーティンエンダー

_nは現在の観測値の番号です。
bmarks


1

SQF、91バイト

params["i"];{n=floor random count i;i set[_forEachIndex,i select n];i set[n,_x]}forEach i;i

1
これは偏っています(Will It Shuffleの「スワップ(i <->ランダム)」を参照)が、に置き換えること%xでFisher-Yates(不偏)に変換できます%i
マーティンエンダー

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