配列からランダムに選択する


19

この課題はかなり単純です。
正の(0を含まない)整数の配列が与えられ、この配列からランダムな要素を選択する必要があります。

しかし、ここにひねりがあります
。要素を選択する確率は整数の値に依存します。つまり、整数が大きくなると、要素が選択される確率も大きくなります。

配列が与えられ[4, 1, 5]ます。

4を選択する確率は、4を配列内のすべての要素の合計で割ったものに等しくなり4 / ( 4 + 1 + 5 ) = 4 / 10 =40%ます(この場合)。
1を選択する確率は1 / 10または10%です。

入力

正の整数の配列。

出力

メソッドを使用している場合は選択した整数を返すか、に直接出力しますstdout

ルール

  • これはので、どの言語でもバイト単位の最短コードが優先されます。
  • 標準的な抜け穴は禁止されています。

回答:


20

ゼリー、3バイト

x`X

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

まあ、Unicodeはありません!

説明:

x`X
 `  Make monad from dyad and use same left and right arguments
x   Repeat each element of the left argument (implicit) list its respective number of times in the right argument list
  X Random element

1
あなたのコードが何をするのか説明してください。:)
イアンH.

1
@IanH。それは本当に単純なアルゴリズムで、各要素自体を何度も繰り返してからランダムに選択します。
エリックアウトゴルファー

16

R、25バイト

function(s)sample(s,1,,s)

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

説明:

function(s){
 sample(x = s, size = 1, replace = FALSE, prob = s)
}

重量なしで、交換せずsにサイズからサンプル1を取得しsます。これらは確率になるように再スケーリングされます。

配布を確認するには、このリンクを使用します。


あなたは9ヶ月までに私を打ち負かしました!:D
JayCe

@JayCeへえ、あなたに対する私の唯一の利点は、あなたがかなりのゴルファーなので「最初に行く」ようです!:-)
ジュゼッペ

13

Pyth、4バイト

OsmR

ここで試してみてください。

@Jakubeのおかげで、かなり珍しいアプローチで1バイト節約されました。

Pyth、5バイト

Osm*]

ここで試してみてください!

どうやって?

#1

OsmR-完全なプログラム。

   R-右のマップ​​...
  m-...マップの使用。これは本質的にリスト[[4,4,4,4]、[1]、[5,5,5,5,5]]を作成します。
       -...これはジャクベにクレジットされます!
 s-フラット化。
O-^のランダム要素。暗黙的に表示します。

#2

Osm *]-完全なプログラム。

  m-入力にマップします。
    ]-現在の要素d、ラップ; [d]。
   *-d回繰り返されました。
 s-フラット化。
O-ランダム要素。結果を暗黙的に印刷します。

1
4でできます。それを台無しにするべきですか、それとも自分で見つけたいですか?
寂部

2
@ジャクベちょっと待って。私にできるか見てみたい。それ明らかですか?
ミスターXcoder

1
@ジャクベOK、あきらめたらpingします。
ミスターXcoder

1
OsmLまたはOsmR
ジャクベ

1
@Jakube Oohそれはとても賢いです!暗黙の引数d、その後d範囲...天才にマップします!
エリックアウトゴルファー

8

CJam(9バイト)

q~_]ze~mR

オンラインデモ。これは、標準入力でCJam配列形式の入力を受け取り、選択した要素を標準出力に出力する完全なプログラムです。

解剖

q~   e# Read and parse input
_]z  e# Copy and transpose
e~   e# Run-length decode
mR   e# Select random element uniformly

1
このような単純なタスクのための非常に強力なゴルフ。
エリックアウトゴルファー

7

Perl 6、20バイト

@Brad Gilbert b2gillsのおかげで1バイト節約されました。

{bag(@_ Zxx@_).pick}

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

これは1つのリスト引数を取ります。xx演算子を使用して、このリストのコピーを2つ圧縮します。したがって@_ Zxx@_、を使用して、要素xx時間で表示されるリストを取得します。次に、に強制されますBag。これは、オブジェクトがコレクションに表示される回数とともにオブジェクトを格納するコレクションです。最後に、このコレクションからを使用してランダムな要素を選択しますpick。これにより、カウントがアカウントに取り込まれ、The Right Thing™が実行されます。


これは短縮できます{bag(@_ Z=>@_).pick}
Brad Gilbert b2gills

@ BradGilbertb2gills、残念ながらそれは機能しません。ペアからバッグを作成します(したがって、「1」は1回、「2」は2回などではありませんが、「1 => 1」は1回、「2 => 2」も1回などです。 。これは、このアドベントカレンダーで説明されているように、作曲家が強要者ではないためです。
ラミリーズ

@ BradGilbertb2gills、しかしとにかくありがとう、あなたは私がここでいくつかのスペースをゴルフするのを助けてくれました、そして他の挑戦でも!
ラミリーズ

意味{bag(@_ Zxx@_).pick}
ブラッドギルバートb2gills

ああ、なるほど。なぜそれが私に起こらなかったのか...:-)ありがとう。
ラミリーズ






4

Java(OpenJDK 8)88 87 86 83バイト

a->{int r=0,x=-1;for(int i:a)r-=i;for(r*=Math.random();r<1;)r+=a[++x];return a[x];}

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


説明を追加してもらえますか?for(r*=Math.random();;)が必要な理由を理解しようとしていますr*=Math.random()
Ayb4btu

@ Ayb4btu for(;;)ループがなければ、for(int i:a)...コンパイラーを満たすために2番目の(決して到達しない)returnステートメントが必要になります-これは3バイト長くなります。
ネベイ

ああ、もちろん、あなたfor(int i:a)foreachC#のようなものです。私は同じ問題を抱えていましたが、ただfor継続的にループを使用していました。あなたの新しい答えは私を興味をそそります。
Ayb4btu

3

J、8 7 8バイト

7バイトは無効です。1〜2日でコンピューターに戻ったら、これを以前の編集に戻します。

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

?@+/{#~

:(配列からランダムな要素を選択するのはコストがかかります。

8バイト

#~{~1?+/

9バイト

(1?+/){#~

説明

?@+/{#~
?        Choose random number in range
  +/     Sum of the array
    {    Select that element from
     #~  The elements duplicated as many times as their value

?@+/です(?@+)/。私は...あなたは再び8へのアップをバンプする必要があります怖い
ホタル

@FireFlyこれをもっとテストすべきだった、いいキャッチ。
コール

3

JavaScript(ES6)、50バイト

a=>a.sort((a,b)=>b-a)[Math.random()**2*a.length|0]

うまくいけば、これがどのように機能するかは明らかですが、とにかくここで説明します。整数を降順でソートし、ベータ分布(1 / 2,1)でランダムに整数を選択します。


これが正しい分布になるとは思わない。私のテストはしていることを示しa=[4,1,5]、あなたは18%程度取得します1、24% 4、および58%5あなたは長さ3のいずれかの入力とその分布を取得します示唆、
ジュゼッペ・

それは私には正しいようです。より高い整数、より高い確率。
kamoroso94

ああなるほど。質問を読み違えました。優れたソリューション、+ 1!
ジュゼッペ


2

PowerShell、27バイト

($args[0]|%{,$_*$_})|Random

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

入力$args[0]をリテラル配列として受け取ります。各要素|%{...}をループし、各反復,$_$_要素の新しい配列を4作成します@(4,4,4,4)。たとえば、これにより配列が作成されます。次に、これらの配列要素がパイプされGet-Random、(疑似)等しい確率で要素の1つが取り出されます。たとえば、@(4,1,5)これは私たちにこれを与えるため、これは@(4,4,4,4,1,5,5,5,5,5)確率要件を満たします。


2

C#(.NET Core)93 89 87 76 + 18 = 94バイト

a=>{int i=-1,r=new Random().Next(a.Sum());while(r>=0)r-=a[++i];return a[i];}

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

追加の18バイト using System.Linq;

謝辞

Nevayのおかげで11バイトが節約されました。Nevayの乱数の実装ははるかに簡潔でした(およびのint代わりにdouble)。

デゴルフド

a=>{
    int i=-1,
    r=new Random().Next(a.Sum());
    while(r>=0)
        r-=a[++i];
    return a[i];
}

説明

r0から要素の合計までの乱数を取得します。次に、各反復でから現在の要素を減算しrます。場合rよりも少ない0場合、この要素を返します。考え方は、配列内の大きな数字には乱数の大きな部分があるということです。


94バイト:a=>{int i=-1,r=new Random().Next(a.Sum());for(;r>=0;)r-=a[++i];return a[i];}
Nevay

2

Japt、7バイト

ËÆD
c ö

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


説明

arrayの暗黙的な入力U

Ë

D現在の要素である関数を介して各要素を渡す配列にマッピングします。

ÆD

長さの配列を生成し、Dそれを埋めDます。

c

平らにします。

ö

ランダムな要素を取得します。



1

Perl、31バイト

@a=map{($_)x$_}@ARGV;$a[rand@a]

これは、入力がコマンドライン引数であると想定しています。数値が大きい場合、メモリが不足する可能性があることに注意してください。




1

、12バイト

F⪪θ;FIι⊞υι‽υ

オンラインでお試しください!リンクは、コードの詳細バージョンです。Charcoalはあまりにも賢くしようとするため、配列にはセミコロン区切りの入力を使用する必要があります。説明:

  θ             Input variable as string
 ⪪ ;            Split on semicolons
F               Loop i over each string
     Iι         Cast i to integer
    F           Repeat that many times
       ⊞υι      Push i to (originally empty) list
          ‽υ    Random selection from list
                Implicitly print


1

Javascript(ES6)、61 54バイト

@Justin Marinerのおかげで-7バイト

a=>a.find(m=>(n-=m)<0,n=Math.random()*eval(a.join`+`))

サンプルコードスニペット

f=
a=>a.find(m=>(n-=m)<0,n=Math.random()*eval(a.join`+`))
console.log(f([4,1,5]))


eval(a.join`+`)代わりにを使用して合計できreduceます。
ジャスティンマリナー

ES7 +とあなたしている場合は、[OK]を使用することができます:[].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+ ))と、コールをinput::[].find(...)
Downgoat

1

Haskell78 77バイト

import System.Random
f l=randomRIO(0,sum l-1)>>=pure.((l>>= \n->n<$[1..n])!!)

オンラインでお試しください!使用例:f [1,99]おそらくyields 99

説明:

  • f整数のリストを取りl、ランダムに選択された整数を次のように返しますIO Int
  • l>>= \n->n<$[1..n]各要素がn繰り返されるリストを作成しますn
  • randomRIO(0,sum l-1) 0から反復要素のリストの長さまでの範囲の整数を生成します。これは、すべての要素の合計から正確に1を引いたもので、範囲外の例外を回避します。

ボーナス: 85バイトのポイントフリーバージョン

import System.Random
(>>=).randomRIO.(,)0.pred.sum<*>(pure.).(!!).(>>= \n->n<$[1..n])

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



1

Java 8、127 122 121バイト

import java.util.*;a->{List l=new Stack();for(int i:a)for(int j=i;j-->0;Collections.shuffle(l))l.add(i);return l.get(0);}

@Nevayのおかげで-1バイト

@ErikTheOutgolferのJelly answerと同様のアプローチを使用して、リストにnアイテムnを追加し、そのリストからランダムに1つ選択します。

説明:

ここで試してみてください。

import java.util.*;        // Required import for List, Stack and Collections
a->{                       // Method with integer-array parameter and integer return-type
  List l=new Stack();      //  Create a List
  for(int i:a)             //  Loop (1) over the input array
    for(int j=i;j-->0;     //   Inner loop (2) from `i` down to 0
        Collections.shuffle(l))
                           //   and shuffle the List randomly after every iteration
      l.add(i);            //    Add `i` that many times to List `l`
                           //   End of inner loop (2) (implicit / single-line body)
                           //  End of loop (1) (implicit / single-line body)
  return l.get(0);         //  And then return the first item of the list
}                          // End of method

1
#shuffle呼び出しをforループに移動して、1バイトを節約できますfor(int j=i;j-->0;Collections.shuffle(l))l.add(i);
ネベイ

@Nevayありがとう!繰り返しごとにリストをシャッフルすることは非常に非効率的ですが、1つの追加の厄介なバイトを取り除くことができる場合、効率、警告などについて何を気にしますか。; p
ケビンクルーッセン


1

GNU APL 1.2、26 23バイト。1.7 21 19バイト

Erik the OutgolferのJelly answerに触発されたアプローチ。⎕IOGNU APLのデフォルトである1ではなく0に依存します(GNU APLの+5バイトの並べ替え⎕IO←0)。

-3、@Zacharýのおかげで-2バイト

関数形式

∇f R
S[?⍴S←∊0 0⍉R∘.⍴R]∇

匿名ラムダ形式

{S[?⍴S←∊0 0⍉⍵∘.⍴⍵]}

説明については、私が使用する関数に渡される引数を表すために、それは同等ですRフォーム。

⍵∘.⍴⍵reshape()演算子を使用してリストの外積を計算します。事実上、これは(乗算テーブルのような)テーブルを作成しますが、乗算する代わりに、列の要素を行の要素と同じ回数だけ繰り返します。質問にある例の場合、これは次のとおりです。

4 4 4 4    1 1 1 1    5 5 5 5   
4          1          5         
4 4 4 4 4  1 1 1 1 1  5 5 5 5 5

0 0⍉⍵∘.⍴⍵行列を転置し、主対角線のみを返します。これにより、行と列⍵∘.⍴⍵が同じ部分、つまりその値に等しい回数を何度も繰り返した部分だけが得られます。例では、これは次のとおりです。

4 4 4 4  1  5 5 5 5 5

引数をリストに変換します。転置()演算子を使用して、3つのベクトルを含むベクトルを得ました。Enlist()は、すべての要素を含む単一のベクトルに変換します。

S←...この新しいベクトルをvectorに割り当てSます。⍴Sリストの長さがわかります。?はランダム演算子であるため?⍴S、0からリストの長さ(排他的)までの乱数を提供します(これが⎕IO0 に依存している理由です。それ以外の場合は1から長さまでです)。S[...]指定されたインデックスの要素を返します。


使用することはないのでQ、必要ありません。そして、IIRCあなたは(関数の最後をマーク小さな三角形のもの。)デルの前に改行を削除することができます
ザカリー

うわー、私<IO> <IO>⍉は主対角線を取得することは決して新しいことではありませんでした!
ザカリー

@ザカリーそうですね。率直に言って、私もこのタスクを試すまで、転置のことを知りませんでした。それを見つけたここに
Arc676

ああ、GNUよりもはるかに優れた無料のAPLが存在します。これはngn APLと呼ばれます。それは実際にはかなりクールです!(ngn.github.io/apl/web、tradfnはありません)
ザカリー

@Zacharý私もそれを持っています:)残念ながら、転置機能は動作しません(または何かを見逃しました)。それがどのように機能するかをよりよく理解できたので、私は再びそれをテストします。
Arc676

1

MATLAB、30バイト

@(a)datasample(repelem(n,n),1)

これは、MATLAB R2015a以降およびStatistics&Machine Learningツールボックスがインストールされていることを前提としています。

repelem使用方法については、以下の説明を参照してください。この短いものと以下のものとの違いは、S&MLツールボックスには、datasample匿名関数を使用できるようにする(均一な確率で)ランダムに配列から1つ以上の要素を取得するために使用できる関数が含まれていることですinput/disp呼び出します。

MATLAB、49バイト

n=input('');a=repelem(n,n);disp(a(randi(nnz(a))))

このコードは、MATLAB R2015a以降がrepelem関数が導入された時点で使用されていることを前提としています。repelemは2つのパラメーターを受け取る関数です。最初のパラメーターは複製される数値の配列であり、2番目のパラメーターは対応する要素が複製される回数の配列です。基本的に、関数は、数値とランレングスを提供することにより、ランレングスのデコードを実行します。

同じ入力を両方の入力に提供するrepelemことにより、意味があれば要素nのn倍以上で構成される配列になります。あなたが提供した[1 2 3]場合、あなたは得るでしょう[1 2 2 3 3 3]。あなたが提供した[1 2 4 2]場合、あなたは得るでしょう[1 2 2 4 4 4 4 2 2]。これを行うことにより、一様な確率で要素を選択した場合(randi(m)1からmまでの一様な確率でランダムな整数を与える)、各要素nが選択される確率がn倍高くなります。最初の例では[1 2 3]11/6のチャンスを持っているでしょう22/6チャンスを持っているでしょうし、33/6チャンスを持っているでしょう。


As a side note, because repelem is not available yet for Octave, I can't give a TIO link. Additionally because Octave can't be used there is a big character penalty as input() and disp() need to be used as an anonymous function is not possible. If Octave supported repelem, the following could be used:

@(n)a(randi(nnz(a=repelem(n,n))))

That would have saved 16 bytes, but it was not to be.


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