배열에서 무작위로 선택


19

이 과제는 다소 간단합니다.
양수 (0을 포함하지 않음)의 배열이 제공되며이 배열에서 임의의 요소를 선택해야합니다.

그러나 비틀기는 다음과 같습니다
. 요소를 선택할 확률은 정수의 값에 따라 달라집니다. 즉 정수가 커질수록 선택 될 확률도 높아집니다!

배열이 제공됩니다 [4, 1, 5].

(4)를 선택하는 확률이 동일하다 어레이의 모든 요소들의 합에 의해 나누어 4 이 경우 4 / ( 4 + 1 + 5 ) = 4 / 10 =40%.
1을 선택할 확률은 1 / 10또는 10%입니다.

입력

양의 정수로 구성된 배열입니다.

산출

메서드를 사용하는 경우 선택한 정수를 반환하거나로 직접 인쇄하십시오 stdout.

규칙

  • 이것은 이므로 모든 언어에서 가장 짧은 바이트 단위의 코드가 승리합니다.
  • 표준 허점은 금지되어 있습니다.

답변:


20

젤리 , 3 바이트

x`X

온라인으로 사용해보십시오!

봐, 유니 코드 없음!

설명:

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
코드의 기능을 설명해 주시겠습니까? :)
Ian H.

1
@IanH. 실제로는 간단한 알고리즘으로 각 요소 자체를 반복 한 다음 무작위로 선택합니다.
Outgolfer Erik

16

R , 25 바이트

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

온라인으로 사용해보십시오!

설명:

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

무게없이 교체없이 s크기 에서 샘플을 채취합니다 . 이것들은 확률로 재조정됩니다.1s

분포를 확인하려면 이 링크를 사용 하십시오 .


9 개월 만에 나를 이겼다! : D
JayCe

@JayCe heh, 당신에 대한 나의 유일한 장점은 당신이 꽤 골퍼이기 때문에 "먼저 가고있다"고! :-)
Giuseppe

13

Pyth , 4 바이트

OsmR

여기에서 시도하십시오.

@Jakube 덕분에 다소 특이한 접근 방식으로 1 바이트를 절약했습니다.

Pyth , 5 바이트

Osm*]

여기 사용해보십시오!

어떻게?

#1

OsmR-전체 프로그램.

   R-오른쪽지도 ...
  m-... 맵 사용. 기본적으로 [[4,4,4,4], [1], [5,5,5,5,5]] 목록이 생성됩니다.
       -... 크레딧이 Jakube에갑니다!
 s-평평하게합니다.
O-^의 임의 원소 암시 적으로 표시합니다.

# 2

Osm *]-전체 프로그램.

  m-입력을 매핑합니다.
    ]-현재 요소 d는 줄 바꿈; [디].
   *-d 번 반복.
 s-평평하게합니다.
O-랜덤 요소. 결과를 암시 적으로 인쇄합니다.

1
4 번에 할 수 있습니다. 망쳐 야합니까, 아니면 직접 찾으시겠습니까?
Jakube

2
@Jakube 조금만 기다려. 내가 할 수 있는지보고 싶어 그것은인가 명백한?
Mr. Xcoder

1
@Jakube 좋아, 내가 포기하면 핑거 야.
Mr. Xcoder

1
OsmL또는OsmR
Jakube

1
@Jakube Ooh 매우 영리합니다! 암시 적 인수 d, d범위 ... 천재에 매핑 !
아웃 골퍼 에릭

8

CJam (9 바이트)

q~_]ze~mR

온라인 데모 . 이것은 stdin에서 CJam 배열 형식으로 입력을 받고 선택된 요소를 stdout에 인쇄하는 전체 프로그램입니다.

해부

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

1
그런 간단한 작업을위한 강력한 골프.
Outgolfer Erik

7

펄 6 , 20 바이트

@Brad Gilbert b2gills 덕분에 1 바이트를 절약했습니다.

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

온라인으로 사용해보십시오!

이것은 1 개의리스트 인수를 취합니다. xx연산자를 사용하여이 목록의 사본 2 개를 압축합니다 . 따라서 @_ Zxx@_, 우리 x는 요소 가 제시 되는 목록을 얻 x습니다. 그런 다음 Bag개체에 컬렉션에 표시되는 횟수와 함께 개체를 저장하는 컬렉션 인에 강제 변환됩니다 . 마지막으로을 사용하여이 컬렉션에서 임의의 요소를 선택합니다.이 요소 pick는 개수를 고려하여 The Right Thing ™을 수행합니다.


이것은 단축 할 수 있습니다{bag(@_ Z=>@_).pick}
브래드 길버트 b2gills

@ BradGilbertb2gills, 슬프게도 작동하지 않습니다. 그것은 한 쌍에서 가방을 만듭니다 (따라서 "1"한 번, "2"두 번 등은 없지만 "1 => 1"한 번, "2 => 2"도 한 번 등등-내가 원하는 것이 아닙니다) . 이 강림절 달력에 설명 된대로 작곡가는 강제적이지 않기 때문 입니다.
Ramillies

@ BradGilbertb2gills, 어쨌든 고마워요. 여기서 다른 공간에서 골프를하는 데 도움이되었습니다!
Ramillies

나는 의미했다{bag(@_ Zxx@_).pick}
브래드 길버트 b2gills

아아 왜 나에게 그런 일이 발생하지 않았습니까 ... :-) 감사합니다.
Ramillies


5

MATL , 8 6 바이트

tY"1Zr

MATL Online 에서 사용해보십시오 !

설명

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 바이트

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)...컴파일러를 만족시키기 위해 두 번째 (절대로 도달하지 않은) return 문이 필요합니다 . 3 바이트 더 깁니다.
Nevay

아, 물론 C # for(int i:a)과 같습니다 foreach. 나는 같은 문제가 있었지만 for계속 반복 되는 것을 사용했다 . 당신의 새로운 대답은 저를 흥미롭게합니다. 나는 당신의 생각을 약간 시도하고 싶을 것입니다.
Ayb4btu

3

J, 8 7 8 바이트

7 바이트는 유효하지 않습니다. 하루나 이틀 안에 컴퓨터로 돌아 오면 이전 편집으로 되돌릴 것입니다.

온라인으로 사용해보십시오!

?@+/{#~

:( 배열에서 임의의 요소를 선택하는 것은 비용이 많이 듭니다.

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

@FireFly 나는 그것을 더 잘 테스트해야합니다.
cole

3

자바 스크립트 (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을 입력하면 분포를 얻을 수 있음을 나타냅니다.
Giuseppe

그것은 나에게 맞는 것 같습니다. 높은 정수, 높은 확률.
kamoroso94

아, 알겠습니다 질문을 잘못 읽었습니다. 탁월한 솔루션, +1!
주세페


2

PowerShell , 27 바이트

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

온라인으로 사용해보십시오!

$args[0]리터럴 배열로 입력 을받습니다. 각 요소를 순환 |%{...}하고 각각의 반복은 새로운 배열 구축 ,$_$_대한 예 - 요소 4이 배열을 생성한다 @(4,4,4,4). 그런 다음 해당 배열 요소가 파이프되어 Get-Random(의사) 동일한 확률로 요소 중 하나를 뽑아냅니다. 예를 들어, @(4,1,5)이것이 우리에게 @(4,4,4,4,1,5,5,5,5,5)확률 요구 사항을 만족시키기 때문에.


2

C # (. NET 코어) , 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 ö

여기에서 테스트


설명

배열의 암시 적 입력 U.

Ë

D현재 요소가 있는 함수를 통해 각 요소를 전달하는 배열을 맵핑하십시오 .

ÆD

길이의 배열을 생성 D하고로 채 웁니다 D.

c

반음 낮추다.

ö

임의의 요소를 가져옵니다.



1

Perl, 31 bytes

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

This assumes the input to be command line arguments. Note that it may run out of memory if the numbers are large.




1

Charcoal, 12 bytes

F⪪θ;FIι⊞υι‽υ

Try it online! Link is to verbose version of code. Since Charcoal tries to be too clever, I'm having to use semicolon-delimited input for the array. Explanation:

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

-7 bytes thanks to @Justin Mariner

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

Example code snippet

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


You can sum by using eval(a.join`+`) instead of reduce.
Justin Mariner

If you're ok with ES7+ you can use: [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+)) and call with input::[].find(...)
Downgoat

1

Haskell, 78 77 bytes

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

Try it online! Usage example: f [1,99] probably yields 99.

Explanation:

  • f takes a list of integers l and returns the randomly selected integer as IO Int.
  • l>>= \n->n<$[1..n] constructs a list with each element n repeated n times.
  • randomRIO(0,sum l-1) yields an integer in the range from 0 to the length of the list of repeated elements, which is exactly the sum of all elements, minus one to avoid a out of bound exception.

Bonus: 85 byte point-free version

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

Try it online!



1

Java 8, 127 122 121 bytes

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 thanks to @Nevay.

Uses a similar approach as @ErikTheOutgolfer's Jelly answer, by adding n times the item n to the list, and then select one randomly from that list.

Explanation:

Try it here.

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
You can move the #shuffle call into the for loop to save 1 byte for(int j=i;j-->0;Collections.shuffle(l))l.add(i);.
Nevay

@Nevay Thanks! Shuffling the List after every iteration is pretty inefficient, but what do we care about efficiency, warnings and such when we can get rid of one additional pesky byte. ;p
Kevin Cruijssen

1

Dyalog APL, 8 bytes

/⍨⌷⍨1?+/

Try it online!

How?

  • /⍨, n copies of n for each n in the argument.
  • ⌷⍨, at the index of
  • 1?, a random value between 1 and
  • +/, the sum of the argument

1

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

Approach inspired by Erik the Outgolfer's Jelly answer. Relies on ⎕IO being 0 instead of 1, which is the default for GNU APL (sort of +5 bytes for ⎕IO←0).

-3, -2 bytes thanks to @Zacharý

function form

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

Anonymous lambda form

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

For the explanation, I will use to represent the argument passed to the function, but it is equivalent to R in the form.

⍵∘.⍴⍵ computes the outer product on the list using the reshape () operator. Effectively, this creates a table (like a multiplication table) but instead of multiplying, it repeats the element in the column a number of times equal to the element in the row. For the example given in the question, this is:

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 the matrix and returns just the main diagonal. This gives us just the parts where the row and column in ⍵∘.⍴⍵ were the same i.e. we repeated the number a number of times equal to its value. For the example, this is:

4 4 4 4  1  5 5 5 5 5

turns its argument into a list. Using the transpose () operator, we got a vector containing 3 vectors. Enlist () turns it into a single vector containing all the elements.

S←... assigns this new vector to vector S. ⍴S gives us the length of that list. ? is the random operator, so ?⍴S gives us a random number between 0 and the length of the list (exclusive) (this is why it relies on ⎕IO being 0; otherwise it's between 1 and the length, inclusive). S[...] returns the element at the given index.


You don't need Q, since you never use it. And IIRC you can remove the newline before the del (little triangle-thing marking the end of the function.)
Zacharý

Wow, I never new <IO> <IO>⍉ to get the main diagonal was even a thing!
Zacharý

@Zacharý Right, thanks. Frankly, I didn't even know about the transpose thing until I tried this task either. Found it here
Arc676

Oh, there does exist a much better free APL than GNU, it's called ngn APL. It's actually pretty cool! (ngn.github.io/apl/web, but it doesn't have tradfn)
Zacharý

@Zacharý I have that one too :) unfortunately the transpose function doesn't work (or I missed something). I will be testing it again now that I have a better understanding of how it works.
Arc676

1

MATLAB, 30 bytes

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

This assumes MATLAB R2015a or newer and with the Statistics & Machine Learning toolbox installed.

See the explanation below for how repelem is used. The difference between this shorter one and the one below is that the S&ML toolbox includes the function datasample which can be used to take one or more elements from an array at random (with uniform probability) which allows an anonymous function to be used, stripping away the input/disp calls.

MATLAB, 49 bytes

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

This code assumes that MATLAB R2015a or newer is used as that is when the repelem function was introduced. repelem is a function which takes two parameters, the first is an array of numbers to be replicated, and the second is an array of how many times the corresponding element should be replicated. Essentially the function performs run-length decoding by providing the number and the run-length.

By providing the same input to both inputs of repelem we end up with an array which consists of n times more of element n if that makes sense. If you provided [1 2 3] you would get [1 2 2 3 3 3]. If you provided [1 2 4 2] you would get [1 2 2 4 4 4 4 2 2]. By doing this it means that if we select an element with uniform probability (randi(m) gives a random integer from 1 to m with uniform probability), each element n has an n times higher probability of being selected. In the first example of [1 2 3], 1 would have a 1/6 chance, 2 would have a 2/6 chance and 3 would have a 3/6 chance.


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.