Chọn ngẫu nhiên từ một mảng


19

Thử thách này khá đơn giản:
Bạn được cung cấp một mảng các số nguyên dương (không bao gồm 0) và phải chọn một phần tử ngẫu nhiên từ mảng này.

Nhưng đây là khuynh hướng:
Xác suất chọn một phần tử phụ thuộc vào giá trị của số nguyên, nghĩa là khi số nguyên phát triển lớn hơn, xác suất của phần tử được chọn cũng vậy!

Thí dụ

Bạn được cung cấp các mảng [4, 1, 5].

Xác suất chọn 4 bằng 4 chia cho tổng của tất cả các phần tử trong mảng , trong trường hợp này 4 / ( 4 + 1 + 5 ) = 4 / 10 =40%.
Xác suất chọn 1 là 1 / 10hoặc 10%.

Đầu vào

Một mảng các số nguyên dương.

Đầu ra

Trả về số nguyên đã chọn nếu sử dụng một phương thức hoặc trực tiếp in nó tới stdout.

Quy tắc

  • Đây là để mã ngắn nhất tính theo byte trong bất kỳ ngôn ngữ nào đều thắng.
  • Sơ hở tiêu chuẩn bị cấm.

Câu trả lời:


20

Thạch , 3 byte

x`X

Hãy thử trực tuyến!

Nhìn này, không có Unicode!

Giải trình:

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
Bạn có thể giải thích những gì mã của bạn làm, xin vui lòng? :)
Ian H.

1
@IanH. Đó thực sự là một thuật toán đơn giản lặp lại mỗi phần tử lần sau đó chọn ngẫu nhiên.
Erik the Outgolfer

16

R , 25 byte

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

Hãy thử trực tuyến!

Giải trình:

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

Lấy một mẫu từ skích thước 1mà không thay thế, với trọng lượng s; những cái này được định cỡ lại là xác suất.

Để xác minh phân phối, sử dụng liên kết này .


bạn đánh bại tôi đến 9 tháng! : D
JayCe

@JayCe heh, lợi thế duy nhất của tôi đối với bạn dường như là "đi trước" vì bạn khá là người chơi gôn! :-)
Giuseppe

13

Bình thường , 4 byte

OsmR

Hãy thử nó ở đây.

Đã lưu một byte, nhờ @Jakube, với cách tiếp cận khá bất thường.

Bình thường , 5 byte

Osm*]

Hãy thử nó ở đây!

Làm sao?

# 1

OsmR - Chương trình đầy đủ.

   R - Bản đồ phải ...
  m - ... Sử dụng Bản đồ. Điều này về cơ bản tạo ra danh sách [[4,4,4,4], [1], [5,5,5,5,5]].
       - ... Tín dụng đến Jakube cho việc này!
 s - Làm phẳng.
O - Phần tử ngẫu nhiên của ^. Hiển thị ngầm.

# 2

Osm *] - Chương trình đầy đủ.

  m - Bản đồ qua đầu vào.
    ] - Phần tử hiện tại, d, bọc; [d].
   * - Lặp đi lặp lại d lần.
 s - Làm phẳng.
O - Phần tử ngẫu nhiên. Ngẫu nhiên in kết quả.

1
Tôi có thể làm điều đó trong 4. Tôi nên làm hỏng nó, hoặc bạn muốn tự mình tìm nó?
Jakube

2
@Jakube Đợi một chút. Muốn xem nếu tôi có thể làm điều đó. Điều đó rõ ràng không?
Ông Xcoder

1
@Jakube Ok, tôi sẽ ping khi tôi bỏ cuộc.
Ông Xcoder

1
OsmLhoặcOsmR
Jakube

1
@Jakube Ooh đó là rất thông minh! Lập luận ngầm d, sau đó ánh xạ dqua một phạm vi ... thiên tài!
Erik the Outgolfer

8

CJam (9 byte)

q~_]ze~mR

Bản demo trực tuyến . Đây là một chương trình đầy đủ lấy đầu vào ở định dạng mảng CJam trên stdin và in phần tử được chọn thành thiết bị xuất chuẩn.

Mổ xẻ

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

1
Một golf mạnh mẽ cho một nhiệm vụ đơn giản như vậy.
Erik the Outgolfer

7

Perl 6 , 20 byte

Đã lưu 1 byte nhờ vào b2gills @Brad Gilbert.

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

Hãy thử trực tuyến!

Điều này có 1 đối số danh sách. Chúng tôi nén 2 bản sao của danh sách này bằng cách sử dụng xxtoán tử. Vì vậy, với @_ Zxx@_, chúng tôi nhận được một danh sách trong đó phần tử xđược trình bày xlần. Sau đó, nó bị ép buộc Bag, đó là một bộ sưu tập lưu trữ các đối tượng cùng với số lần chúng xuất hiện trong bộ sưu tập. Cuối cùng, chúng tôi chọn một yếu tố ngẫu nhiên từ bộ sưu tập này pick, trong đó lấy số đếm vào tài khoản và thực hiện The Right Thing ™.


Điều này có thể được rút ngắn thành{bag(@_ Z=>@_).pick}
Brad Gilbert b2gills

@ BradGilbertb2gills, thật đáng buồn là nó không hoạt động. Nó tạo ra một chiếc túi từ các cặp (vì vậy sẽ không có "1" một lần, "2" hai lần, v.v., nhưng "1 => 1" một lần, "2 => 2" cũng một lần, v.v. - không phải những gì tôi muốn) . Đó là bởi vì các nhà soạn nhạc không phải là người cưỡng chế, như đã giải thích trong Lịch Mùa Vọng này .
Ramillies

@ BradGilbertb2gills, nhưng dù sao cũng cảm ơn bạn, bạn đã giúp tôi chơi gôn ở một số không gian ở đây và trong các thử thách khác nữa!
Ramillies

Ý tôi là{bag(@_ Zxx@_).pick}
Brad Gilbert b2gills

À, tôi hiểu rồi. Tại sao nó không xảy ra với tôi ...: -) Cảm ơn.
Ramillies


5

MATL , 8 6 byte

tY"1Zr

Hãy thử nó tại MATL Online!

Giải trình

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




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

Hãy thử trực tuyến!


Bạn có thể thêm một lời giải thích? Tôi đang cố gắng để hiểu tại sao for(r*=Math.random();;)cần thiết, hoặc nếu tất cả những gì bạn cần là r*=Math.random().
Ayb4btu

@ Ayb4btu Nếu không có for(;;)vòng lặp, điều này sẽ yêu cầu một câu lệnh trả về thứ hai (không bao giờ đạt được) sau for(int i:a)...để thỏa mãn trình biên dịch - sẽ dài hơn 3 byte.
Nevay

Ah, tất nhiên, bạn for(int i:a)giống như foreachtrong C #. Tôi đã có cùng một vấn đề, nhưng chỉ sử dụng một forvòng lặp liên tục. Câu trả lời mới của bạn gây tò mò cho tôi, tôi có thể thử và ăn cắp một số ý tưởng của bạn.
Ayb4btu

3

J, 8 7 8 byte

7 byter không hợp lệ; Tôi sẽ hoàn nguyên bản chỉnh sửa này trước khi tôi quay lại máy tính của mình sau một hoặc hai ngày.

Hãy thử trực tuyến!

?@+/{#~

:( chọn các yếu tố ngẫu nhiên từ một mảng là tốn kém.

8 byte

#~{~1?+/

9 byte

(1?+/){#~

Giải trình

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

?@+/(?@+)/; Tôi e rằng bạn sẽ phải trả lại tới 8 lần nữa
FireFly

@FireFly Tôi nên thử nó nhiều hơn, bắt tốt.
cole

3

JavaScript (ES6), 50 byte

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

Hy vọng rằng nó rõ ràng làm thế nào điều này hoạt động, nhưng dù sao tôi sẽ giải thích nó ở đây. Nó sắp xếp các số nguyên theo thứ tự giảm dần, sau đó chọn một số ngẫu nhiên với phân phối beta (1 / 2.1) .


Tôi không nghĩ rằng điều này sẽ có phân phối chính xác. Các thử nghiệm của tôi cho thấy rằng a=[4,1,5], bạn sẽ nhận được khoảng 18% 1, 24% 4và 58% 5, điều đó cho thấy bạn sẽ nhận được phân phối đó với bất kỳ đầu vào nào có độ dài 3.
Giuseppe

Điều đó có vẻ đúng với tôi. Số nguyên cao hơn, xác suất cao hơn.
kamoroso94

Ồ, tôi hiểu rồi. Tôi đọc sai câu hỏi. Giải pháp tuyệt vời, +1!
Giuseppe


2

PowerShell , 27 byte

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

Hãy thử trực tuyến!

Đưa đầu vào $args[0]như một mảng theo nghĩa đen. Các vòng lặp thông qua mỗi phần tử |%{...}và mỗi lần lặp sẽ xây dựng một mảng ,$_các $_phần tử mới - ví dụ, 4điều này sẽ tạo ra một mảng @(4,4,4,4). Những phần tử mảng đó sau đó được dẫn vào Get-Randomđó sẽ lấy ra một trong các phần tử có xác suất bằng (giả). Vì, ví dụ, đối với @(4,1,5)điều này cho chúng ta @(4,4,4,4,1,5,5,5,5,5)điều này thỏa mãn các yêu cầu xác suất.


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

Hãy thử trực tuyến!

Thêm 18 byte cho using System.Linq;

Lời cảm ơn

11 byte được lưu nhờ vào Nevay, có triển khai số ngẫu nhiên ngắn gọn hơn rất nhiều (cũng như intthay vì a double).

Bị khử

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

Giải trình

Lấy một số ngẫu nhiên r, giữa 0 và tổng các phần tử. Sau đó, tại mỗi lần lặp lại trừ phần tử hiện tại từ r. Nếu rnhỏ hơn 0, thì trả về phần tử này. Ý tưởng là có những phần lớn hơn của số ngẫu nhiên cho những số lớn hơn trong mảng.


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 ö

Kiểm tra nó ở đây


Giải trình

Đầu vào ngầm định của mảng U.

Ë

Ánh xạ qua mảng đi qua từng phần tử thông qua một hàm trong đó Dlà phần tử hiện tại.

ÆD

Tạo một mảng chiều dài Dvà điền vào nó D.

c

Làm phẳng.

ö

Lấy một yếu tố ngẫu nhiên.



1

Perl, 31 byte

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

Điều này giả sử đầu vào là đối số dòng lệnh. Lưu ý rằng nó có thể hết bộ nhớ nếu số lượng lớn.




1

Than , 12 byte

F⪪θ;FIι⊞υι‽υ

Hãy thử trực tuyến! Liên kết là phiên bản dài dòng của mã. Vì Char than cố gắng quá thông minh, tôi phải sử dụng đầu vào được phân cách bằng dấu chấm phẩy cho mảng. Giải trình:

  θ             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 byte

-7 byte nhờ @Justin Mariner

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

Đoạn mã ví dụ

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


Bạn có thể tổng hợp bằng cách sử dụng eval(a.join`+`)thay vì reduce.
Justin Mariner

Nếu bạn ổn với ES7 +, bạn có thể sử dụng: [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+ ))và gọi bằnginput::[].find(...)
Downgoat

1

Haskell , 78 77 byte

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

Hãy thử trực tuyến! Ví dụ sử dụng:f [1,99] có thể mang lại 99.

Giải trình:

  • flấy danh sách các số nguyên lvà trả về số nguyên được chọn ngẫu nhiên làIO Int .
  • l>>= \n->n<$[1..n] xây dựng một danh sách với từng yếu tố n lặp lạin .
  • randomRIO(0,sum l-1) mang lại một số nguyên trong phạm vi từ 0 đến độ dài của danh sách các phần tử lặp lại, chính xác là tổng của tất cả các phần tử, trừ đi một phần tử để tránh ngoại lệ bị ràng buộc.

Phần thưởng: Phiên bản miễn phí 85 byte

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

Hãy thử trực tuyến!



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 nhờ @Nevay .

Sử dụng một cách tiếp cận tương tự như câu trả lời Jelly của @ErikTheOutgolfer , bằng cách thêm nlần vào mụcn vào danh sách, sau đó chọn ngẫu nhiên một từ danh sách đó.

Giải trình:

Hãy thử nó ở đây.

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
Bạn có thể di chuyển #shufflecuộc gọi vào vòng lặp for để lưu 1 byte for(int j=i;j-->0;Collections.shuffle(l))l.add(i);.
Nevay

@Nevay Cảm ơn! Xáo trộn Danh sách sau mỗi lần lặp là khá kém hiệu quả, nhưng chúng ta quan tâm đến hiệu quả, cảnh báo và như thế nào khi chúng ta có thể loại bỏ một byte pesky bổ sung. ; p
Kevin Cruijssen


1

GNU APL 1.2, 26 23 byte; 1.7 21 19 byte

Cách tiếp cận lấy cảm hứng từ câu trả lời Jelly của Erik the Outgolfer . Dựa vào ⎕IO0 thay vì 1, là mặc định cho GNU APL (loại +5 byte cho ⎕IO←0).

-3, -2 byte nhờ @ Zacharý

dạng hàm

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

Mẫu lambda ẩn danh

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

Để giải thích, tôi sẽ sử dụng để biểu diễn đối số được truyền cho hàm, nhưng nó tương đương với Rtrong biểu mẫu.

⍵∘.⍴⍵tính toán sản phẩm bên ngoài trong danh sách bằng cách sử dụng toán tử reshape ( ). Thực tế, điều này tạo ra một bảng (giống như bảng nhân) nhưng thay vì nhân, nó lặp lại phần tử trong cột một số lần bằng với phần tử trong hàng. Đối với ví dụ được đưa ra trong câu hỏi, đây là:

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⍉⍵∘.⍴⍵hoán vị ma trận và trả về chỉ đường chéo chính. Điều này chỉ cho chúng ta các phần trong đó hàng và cột ⍵∘.⍴⍵giống nhau, nghĩa là chúng ta lặp lại số lượng một số lần bằng giá trị của nó. Ví dụ, đây là:

4 4 4 4  1  5 5 5 5 5

biến đối số của nó thành một danh sách. Sử dụng toán tử transpose ( ), chúng ta có một vectơ chứa 3 vectơ. Enlist ( ) biến nó thành một vectơ duy nhất chứa tất cả các phần tử.

S←...gán vector mới này cho vector S. ⍴Scho chúng tôi độ dài của danh sách đó. ?là toán tử ngẫu nhiên, do đó ?⍴Scung cấp cho chúng tôi một số ngẫu nhiên trong khoảng từ 0 đến độ dài của danh sách (độc quyền) (đây là lý do tại sao nó phụ thuộc vào ⎕IO0; nếu không, nó nằm trong khoảng từ 1 đến độ dài, bao gồm). S[...]trả về phần tử tại chỉ mục đã cho.


Bạn không cần Q, vì bạn không bao giờ sử dụng nó. Và IIRC bạn có thể xóa dòng mới trước del (điều tam giác nhỏ đánh dấu sự kết thúc của chức năng.)
Zacharý

Wow, tôi không bao giờ mới <IO> <IO>⍉để có được đường chéo chính thậm chí là một điều!
Zacharý

@ Zacharý Đúng rồi, cảm ơn. Thành thật mà nói, tôi thậm chí còn không biết về điều chuyển đổi cho đến khi tôi thử nhiệm vụ này. Tìm thấy nó ở đây
Arc676

Ồ, có tồn tại một APL miễn phí tốt hơn nhiều so với GNU, nó được gọi là APL ngn. Nó thật sự rất tuyệt! ( ngn.github.io/apl/web , nhưng nó không có tradfn)
Zacharý

@ Zacharý Tôi cũng có cái đó :) thật không may chức năng chuyển đổi không hoạt động (hoặc tôi đã bỏ lỡ điều gì đó). Bây giờ tôi sẽ kiểm tra lại nó để tôi hiểu rõ hơn về cách thức hoạt động của nó.
Arc676

1

MATLAB, 30 byte

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

Điều này giả định MATLAB R2015a hoặc mới hơn và với hộp công cụ Thống kê & Máy học được cài đặt.

Xem giải thích dưới đây để biết cách repelemsử dụng. Sự khác biệt giữa cái ngắn hơn và cái dưới đây là hộp công cụ S & ML bao gồm chức năng datasamplecó thể được sử dụng để lấy một hoặc nhiều phần tử từ một mảng một cách ngẫu nhiên (với xác suất đồng nhất) cho phép sử dụng một hàm ẩn danh, loại bỏ hàminput/disp các cuộc gọi.

MATLAB, 49 byte

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

Mã này giả định rằng MATLAB R2015a hoặc mới hơn được sử dụng vì đó là khi repelemchức năng được giới thiệu.repelemlà một hàm có hai tham số, đầu tiên là một mảng các số được sao chép và thứ hai là một mảng bao nhiêu lần phần tử tương ứng sẽ được sao chép. Về cơ bản, hàm thực hiện giải mã độ dài chạy bằng cách cung cấp số lượng và độ dài chạy.

Bằng cách cung cấp cùng một đầu vào cho cả hai đầu vào của repelemchúng ta, kết thúc bằng một mảng bao gồm n phần tử nhiều hơn n lần nếu điều đó có ý nghĩa. Nếu bạn cung cấp, [1 2 3]bạn sẽ nhận được [1 2 2 3 3 3]. Nếu bạn cung cấp, [1 2 4 2]bạn sẽ nhận được [1 2 2 4 4 4 4 2 2]. Bằng cách này, điều đó có nghĩa là nếu chúng ta chọn một phần tử có xác suất đồng nhất ( randi(m)đưa ra một số nguyên ngẫu nhiên từ 1 đến m với xác suất đồng nhất), thì mỗi phần tử n có xác suất được chọn cao hơn n lần. Trong ví dụ đầu tiên [1 2 3], 1sẽ có cơ hội 1/6, 2sẽ có cơ hội 2/6 và 3sẽ có cơ hội 3/6.


Là một lưu ý phụ, vì repelemchưa có sẵn cho Octave, tôi không thể cung cấp liên kết TIO. Ngoài ra, vì Octave không thể được sử dụng nên có một hình phạt nhân vật lớn input()disp()không thể sử dụng như một chức năng ẩn danh. Nếu Octave được hỗ trợ repelem, có thể sử dụng các mục sau:

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

Điều đó sẽ tiết kiệm được 16 byte, nhưng thực tế không phải vậy.


Thực sự đánh giá cao lời giải thích, cảm ơn!
Ian H.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.