Pilih secara acak dari sebuah array

19

Tantangan ini agak sederhana:
Anda diberi array bilangan bulat positif (tidak termasuk 0), dan harus memilih elemen acak dari array ini.

Tapi inilah twistnya:
Probabilitas memilih elemen tergantung pada nilai integer, artinya ketika integer tumbuh lebih besar, probabilitas untuk dipilih juga!

Contoh

Anda diberi array [4, 1, 5].

Probabilitas memilih 4 sama dengan 4 dibagi dengan jumlah semua elemen dalam array , dalam hal ini 4 / ( 4 + 1 + 5 ) = 4 / 10 =40%.
Probabilitas memilih 1 adalah 1 / 10atau 10%.

Memasukkan

Array bilangan bulat positif.

Keluaran

Kembalikan bilangan bulat yang dipilih jika menggunakan metode, atau langsung cetak ke stdout.

Aturan

  • Ini adalah sehingga kode terpendek dalam byte menang dalam bahasa apa pun.
  • Celah standar dilarang.
Ian H.
sumber

Jawaban:

20

Jelly , 3 byte

x`X

Cobalah online!

Lihat bu, bukan Unicode!

Penjelasan:

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
Erik the Outgolfer
sumber
1
Bisakah Anda menjelaskan apa yang kode Anda lakukan? :)
Ian H.
1
@IanH. Ini benar-benar algoritma sederhana, ulangi setiap elemen itu sendiri kali kemudian pilih secara acak.
Erik the Outgolfer
16

R , 25 byte

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

Cobalah online!

Penjelasan:

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

Mengambil sampel dari sukuran 1tanpa penggantian, dengan bobot s; ini di-rescaled menjadi probabilitas.

Untuk memverifikasi distribusi, gunakan tautan ini .

Giuseppe
sumber
Anda mengalahkan saya sampai 9 bulan! : D
JayCe
@JayCe heh, satu-satunya keunggulan saya atas Anda tampaknya "pergi dulu" karena Anda cukup pegolf! :-)
Giuseppe
13

Pyth , 4 byte

OsmR

Coba di sini.

Disimpan satu byte, terima kasih kepada @Jakube, dengan pendekatan yang agak tidak biasa.

Pyth , 5 byte

Osm*]

Coba di sini!

Bagaimana?

# 1

OsmR - Program lengkap.

   R - Peta Kanan ...
  m - ... Menggunakan Peta. Ini pada dasarnya menciptakan daftar [[4,4,4,4], [1], [5,5,5,5,5]].
       - ... Kredit jatuh ke Jakube untuk ini!
 s - Ratakan.
O - Elemen acak ^. Tampilan secara implisit.

# 2

Osm *] - Program lengkap.

  m - Peta atas input.
    ] - Elemen saat ini, d, dibungkus; [d].
   * - D berulang kali.
 s - Ratakan.
O - Elemen Acak. Cetak hasilnya secara implisit.
Tuan Xcoder
sumber
1
Saya dapat melakukannya di 4. Haruskah saya merusaknya, atau Anda ingin menemukannya sendiri?
Jakube
2
@ Jakube Tunggu sebentar. Ingin tahu apakah saya bisa melakukannya. Apakah itu jelas?
Tn. Xcoder
1
@ Jakube Ok, saya akan ping ketika saya menyerah.
Tn. Xcoder
1
OsmLatauOsmR
Jakube
1
@ Jakube Ooh itu sangat pintar! Argumen implisit d, lalu petakan dpada rentang ... jenius!
Erik the Outgolfer
8

CJam (9 byte)

q~_]ze~mR

Demo online . Ini adalah program lengkap yang mengambil input dalam format array CJam pada stdin dan mencetak elemen yang dipilih ke stdout.

Pembedahan

q~   e# Read and parse input
_]z  e# Copy and transpose
e~   e# Run-length decode
mR   e# Select random element uniformly
Peter Taylor
sumber
1
Golf yang sangat kuat untuk tugas yang sederhana.
Erik the Outgolfer
7

Perl 6 , 20 byte

Disimpan 1 byte berkat @Brad Gilbert b2gills.

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

Cobalah online!

Ini membutuhkan 1 argumen daftar. Kami menyalin 2 salinan daftar ini menggunakan xxoperator. Jadi dengan @_ Zxx@_, kita mendapatkan daftar di mana elemen xdisajikan xkali. Itu kemudian dipaksa Bag, yang merupakan koleksi yang menyimpan objek bersama dengan berapa kali mereka muncul dalam koleksi. Akhirnya, kami memilih elemen acak dari koleksi ini pick, yang memasukkan jumlah ke dalam akun dan melakukan The Right Thing ™.

Ramillies
sumber
Ini dapat disingkat menjadi{bag(@_ Z=>@_).pick}
Brad Gilbert b2gills
@ BradGilbertb2gills, sayangnya itu tidak berhasil. Itu membuat tas dari pasangan (jadi tidak akan ada "1" sekali, "2" dua kali dll, tetapi "1 => 1" sekali, "2 => 2" juga sekali dll - bukan yang saya inginkan) . Itu karena komposer bukanlah pemaksa, seperti dijelaskan dalam Kalender Advent ini .
Ramillies
@ BradGilbertb2gills, tetapi terima kasih, Anda membantu saya bermain golf di sini dan di tantangan lain juga!
Ramillies
Maksud saya{bag(@_ Zxx@_).pick}
Brad Gilbert b2gills
Aah, begitu. Mengapa tidak terpikir oleh saya ...: -) Terima kasih.
Ramillies
6

Python 3.6 , 44 byte

lambda A:choices(A,A)[0]
from random import*

Yay untuk built-in. Yang lain Adi choices(A, A)adalah opsional weightsargumen.

Cobalah online!

shooqie
sumber
5

MATL , 8 6 byte

tY"1Zr

Cobalah di MATL Online!

Penjelasan

t    % Implicit input. Duplicate
Y"   % Run-length decoding
1Zr  % Randomly take one value with uniform distribution. Implicitly display
Luis Mendo
sumber
5

Mathematica, 19 byte

RandomChoice[#->#]&
J42161217
sumber
4

Python 3 , 62 byte

lambda k:choice(sum([x*[x]for x in k],[]))
from random import*

Cobalah online!

Tuan Xcoder
sumber
4

Java (OpenJDK 8) , 88 87 86 83 byte

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

Cobalah online!

Nevay
sumber
Bisakah Anda menambahkan penjelasan? Saya mencoba memahami mengapa for(r*=Math.random();;)ini diperlukan, atau jika semua yang Anda butuhkan r*=Math.random().
Ayb4btu
@ Ayb4btu Tanpa for(;;)loop ini akan membutuhkan pernyataan kembali kedua (tidak pernah tercapai) setelah for(int i:a)...untuk memenuhi kompiler - yang akan menjadi 3 byte lebih lama.
Nevay
Ah, tentu saja, Anda for(int i:a)seperti foreachdi C #. Saya memiliki masalah yang sama, tetapi hanya menggunakan forloop yang terus menerus. Jawaban baru Anda membuat saya penasaran, saya mungkin mencoba dan mencuri beberapa ide Anda.
Ayb4btu
3

J, 8 7 8 byte

7 byter tidak valid; Saya akan mengembalikan ini ke suntingan sebelumnya ketika saya kembali ke komputer saya dalam satu atau dua hari.

Cobalah online!

?@+/{#~

:( memilih elemen acak dari sebuah array itu mahal.

8 byte

#~{~1?+/

9 byte

(1?+/){#~

Penjelasan

?@+/{#~
?        Choose random number in range
  +/     Sum of the array
    {    Select that element from
     #~  The elements duplicated as many times as their value
cole
sumber
?@+/adalah (?@+)/; Saya khawatir Anda harus menabraknya hingga 8 lagi ...
FireFly
@ Kebakaran Saya harus mengujinya lebih, tangkapan yang bagus.
cole
3

JavaScript (ES6), 50 byte

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

Semoga ini jelas bagaimana ini bekerja, tetapi saya akan menjelaskannya di sini. Ini mengurutkan bilangan bulat dalam urutan menurun, lalu memilih satu secara acak dengan distribusi beta (1 / 2,1) .

kamoroso94
sumber
Saya tidak berpikir ini akan memiliki distribusi yang benar. Tes saya menunjukkan bahwa dengan a=[4,1,5], Anda akan mendapatkan sekitar 18% 1, 24% 4, dan 58% 5, yang menunjukkan Anda akan mendapatkan distribusi itu dengan input panjang 3.
Giuseppe
Sepertinya itu benar bagi saya. Bilangan bulat lebih tinggi, probabilitas lebih tinggi.
kamoroso94
Oh begitu. Saya salah membaca pertanyaan. Solusi luar biasa, +1!
Giuseppe
2

PowerShell , 27 byte

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

Cobalah online!

Mengambil input $args[0]sebagai array literal. Loop melalui setiap elemen |%{...}dan setiap iterasi membangun sebuah array baru ,$_dari $_elemen - misalnya, untuk 4ini akan menciptakan sebuah array @(4,4,4,4). Elemen-elemen array tersebut kemudian disalurkan ke Get-Randommana akan memetik salah satu elemen dengan probabilitas (pseudo) yang sama. Karena, misalnya, untuk @(4,1,5)ini memberi kita @(4,4,4,4,1,5,5,5,5,5)ini memenuhi persyaratan probabilitas.

AdmBorkBork
sumber
2

C # (.NET Core) , 93 89 87 76 + 18 = 94 byte

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

Cobalah online!

Tambahan 18 byte untuk using System.Linq;

Ucapan Terima Kasih

11 byte disimpan berkat Nevay, yang penerapan angka acaknya jauh lebih ringkas (dan juga intbukan a double).

Merosot

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

Penjelasan

Dapatkan angka acak r,, antara 0 dan jumlah elemen. Kemudian pada setiap iterasi kurangi elemen saat ini dari r. Jika rkurang dari 0, maka kembalikan elemen ini. Idenya adalah bahwa ada bagian yang lebih besar dari angka acak untuk angka yang lebih besar dalam array.

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

Japt , 7 byte

ËÆD
c ö

Uji di sini


Penjelasan

Input array secara implisit U.

Ë

Peta di atas array yang melewati setiap elemen melalui fungsi di mana Delemen saat ini.

ÆD

Hasilkan array panjang Ddan isi dengan D.

c

Meratakan.

ö

Dapatkan elemen acak.

Shaggy
sumber
2

CJam , 5 byte

lS/mR

Cobalah online! Catatan: pisahkan angka dengan spasi

lolad
sumber
1

Perl, 31 byte

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

Ini mengasumsikan input menjadi argumen baris perintah. Perhatikan bahwa mungkin kehabisan memori jika jumlahnya besar.


sumber
1

Perl 5 , 31 + 1 (-a) = 32 byte

@p=map{($_)x$_}@F;say$p[rand@p]

Cobalah online!

Xcali
sumber
1

Arang , 12 byte

F⪪θ;FIι⊞υι‽υ

Cobalah online! Tautan adalah untuk mengucapkan versi kode. Karena Charcoal mencoba menjadi terlalu pintar, saya harus menggunakan input titik koma untuk array. Penjelasan:

  θ             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
Neil
sumber
1

Haskell , 87 byte

import System.Random
f l|m<-[x<$[1..x]|x<-l]>>=id=randomRIO(0,length m-1)>>=print.(m!!)

Cobalah online!

jferard
sumber
1

Javascript (ES6), 61 54 byte

-7 byte terima kasih kepada @Justin Mariner

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

Cuplikan kode contoh

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

Herman L.
sumber
Anda dapat menjumlahkan dengan menggunakan eval(a.join`+`)alih-alih reduce.
Justin Mariner
Jika Anda setuju dengan ES7 +, Anda dapat menggunakan: [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+ ))dan menelepon denganinput::[].find(...)
Downgoat
1

Haskell , 78 77 byte

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

Cobalah online! Contoh penggunaan:f [1,99] mungkin menghasilkan 99.

Penjelasan:

  • f mengambil daftar bilangan bulat l dan mengembalikan bilangan bulat yang dipilih secara acak sebagaiIO Int .
  • l>>= \n->n<$[1..n] membangun daftar dengan setiap elemen n diulangn kali.
  • randomRIO(0,sum l-1) menghasilkan bilangan bulat dalam rentang dari 0 hingga panjang daftar elemen berulang, yang merupakan jumlah keseluruhan dari semua elemen, minus satu untuk menghindari pengecualian yang tidak terikat.

Bonus: versi bebas byte 85 byte

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

Cobalah online!

Laikoni
sumber
1

Bash , 51 byte

for n in $@;{ printf $n\\n%.s `seq $n`;}|shuf|sed q

Mengambil input yang dipisahkan oleh spasi atau dipisahkan oleh baris baru dalam satu argumen atau beberapa argumen.

Cobalah online!

Validasi frekuensi acak dengan test case yang lebih rumit.

Justin Mariner
sumber
1

Java 8, 127 122 121 byte

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);}

-1 byte terima kasih kepada @Nevay .

Gunakan pendekatan yang mirip dengan jawaban Jelly @ErikTheOutgolfer , dengan menambahkan nkali item nke daftar, lalu pilih satu secara acak dari daftar itu.

Penjelasan:

Coba di sini.

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
Kevin Cruijssen
sumber
1
Anda dapat memindahkan #shufflepanggilan ke loop untuk menyimpan 1 byte for(int j=i;j-->0;Collections.shuffle(l))l.add(i);.
Nevay
@Tidak, Terima kasih! Mengocok Daftar setelah setiap iterasi cukup tidak efisien, tetapi apa yang kita pedulikan tentang efisiensi, peringatan dan semacamnya ketika kita dapat menyingkirkan satu byte tambahan yang sial. ; p
Kevin Cruijssen
1

Dyalog APL , 8 byte

/⍨⌷⍨1?+/

Cobalah online!

Bagaimana?

  • /⍨, nsalinan nuntuk masing-masing ndalam argumen.
  • ⌷⍨, pada indeks
  • 1?, nilai acak antara 1dan
  • +/, jumlah argumen
Zacharý
sumber
1

GNU APL 1.2, 26 23 bytes; 1,7 21 19 byte

Pendekatan terinspirasi oleh jawaban Erik the Outgolfer's Jelly . Bergantung pada ⎕IO0 bukan 1, yang merupakan default untuk GNU APL (semacam +5 byte untuk⎕IO←0 ).

-3, -2 bytes berkat @ Zacharý

bentuk fungsi

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

Formulir lambda anonim

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

Untuk penjelasannya, saya akan gunakan untuk mewakili argumen yang dilewatkan ke fungsi, tetapi itu setara dengan Rdalam bentuk.

⍵∘.⍴⍵menghitung produk luar pada daftar menggunakan operator membentuk kembali ( ). Secara efektif, ini membuat tabel (seperti tabel perkalian) tetapi alih-alih mengalikannya, ia mengulangi elemen di kolom beberapa kali sama dengan elemen di baris. Untuk contoh yang diberikan dalam pertanyaan, ini adalah:

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⍉⍵∘.⍴⍵transposes matriks dan hanya mengembalikan diagonal utama. Ini memberi kita hanya bagian di mana baris dan kolom dalam ⍵∘.⍴⍵adalah sama yaitu kita mengulangi angka beberapa kali sama dengan nilainya. Sebagai contoh, ini adalah:

4 4 4 4  1  5 5 5 5 5

mengubah argumennya menjadi daftar. Menggunakan operator transpose ( ), kami mendapat vektor yang berisi 3 vektor. Daftar ( ) mengubahnya menjadi satu vektor yang berisi semua elemen.

S←...menetapkan vektor baru ini ke vektor S. ⍴Smemberi kita panjang dari daftar itu. ?adalah operator acak, jadi ?⍴Sberi kami angka acak antara 0 dan panjang daftar (eksklusif) (inilah sebabnya ia bergantung pada ⎕IO0; jika tidak, antara 1 dan panjangnya, termasuk). S[...]mengembalikan elemen pada indeks yang diberikan.

Arc676
sumber
Anda tidak perlu Q, karena Anda tidak pernah menggunakannya. Dan IIRC Anda dapat menghapus baris baru sebelum del (hal segitiga kecil yang menandai akhir fungsi.)
Zacharý
Wow, saya tidak pernah baru <IO> <IO>⍉untuk mendapatkan diagonal utama bahkan hal!
Zacharý
@ Zacharý Benar, terima kasih. Terus terang, saya bahkan tidak tahu tentang hal transpose sampai saya mencoba tugas ini juga. Ditemukan di sini
Arc676
Oh, memang ada APL gratis yang jauh lebih baik daripada GNU, itu disebut ngn APL. Ini sebenarnya sangat keren! ( ngn.github.io/apl/web , tetapi tidak memiliki tradfn)
Zacharý
@ Zacharý Saya juga memilikinya :) sayangnya fungsi transpose tidak berfungsi (atau saya melewatkan sesuatu). Saya akan mengujinya lagi sekarang karena saya memiliki pemahaman yang lebih baik tentang cara kerjanya.
Arc676
1

MATLAB, 30 byte

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

Ini mengasumsikan MATLAB R2015a atau lebih baru dan dengan toolbox Statistics & Machine Learning diinstal.

Lihat penjelasan di bawah ini untuk cara repelempenggunaannya. Perbedaan antara yang lebih pendek dan yang di bawah ini adalah bahwa kotak alat S&ML mencakup fungsi datasampleyang dapat digunakan untuk mengambil satu atau lebih elemen dari array secara acak (dengan probabilitas seragam) yang memungkinkan digunakannya fungsi anonim, menghilangkaninput/disp panggilan.

MATLAB, 49 byte

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

Kode ini mengasumsikan bahwa MATLAB R2015a atau yang lebih baru digunakan saat repelemfungsi diperkenalkan.repelemadalah fungsi yang mengambil dua parameter, yang pertama adalah array angka untuk direplikasi, dan yang kedua adalah array berapa kali elemen yang sesuai harus direplikasi. Pada dasarnya fungsi melakukan decoding run-length dengan memberikan nomor dan run-length.

Dengan memberikan input yang sama untuk kedua input repelemkita berakhir dengan sebuah array yang terdiri dari n kali lebih banyak elemen n jika itu masuk akal. Jika Anda memberi [1 2 3]Anda akan mendapatkan [1 2 2 3 3 3]. Jika Anda memberi [1 2 4 2]Anda akan mendapatkan [1 2 2 4 4 4 4 2 2]. Dengan melakukan ini berarti jika kita memilih elemen dengan probabilitas seragam (randi(m) memberikan bilangan bulat acak dari 1 ke m dengan probabilitas seragam), setiap elemen n memiliki probabilitas n kali lebih tinggi untuk dipilih. Pada contoh pertama [1 2 3], 1akan memiliki peluang 1/6, 2akan memiliki peluang 2/6 dan 3akan memiliki peluang 3/6.


Sebagai catatan tambahan, karena repelembelum tersedia untuk Octave, saya tidak dapat memberikan tautan TIO. Selain itu karena Oktaf tidak dapat digunakan ada hukuman karakter besar karena input()dan tidak disp()perlu digunakan sebagai fungsi anonim. Jika Oktaf didukung repelem, berikut ini dapat digunakan:

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

Itu akan menghemat 16 byte, tetapi itu tidak terjadi.

Tom Carpenter
sumber
Sangat menghargai penjelasannya, terima kasih!
Ian H.