Випадково виберіть з масиву


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
Чи можете ви пояснити, що робить ваш код? :)
Ian H.

1
@IanH. Це дійсно простий алгоритм повторення кожного елемента сам раз, а потім вибирайте випадковим чином.
Erik the Outgolfer

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, з досить незвичним підходом.

Pyth , 5 байт

Osm*]

Спробуйте тут!

Як?

№1

OsmR - Повна програма.

   R - правильна карта ...
  м - ... Використання карти. Це по суті створює список [[4,4,4,4], [1], [5,5,5,5,5]].
       - ... Заслуга Якубе за це!
 s - згладити.
O - Випадковий елемент ^. Відображати неявно.

№2

Osm *] - Повна програма.

  m - Карта над входом.
    ] - Поточний елемент, d, обернутий; [г].
   * - Неодноразово d разів.
 s - згладити.
O - Випадковий елемент. Непередбачувано надрукуйте результат.

1
Я можу це зробити в 4. Якщо я його зіпсую, чи ви хочете знайти його самостійно?
Jakube

2
@Jakube Почекайте трохи. Хочу побачити, чи можу я це зробити. Є чи це , що очевидно?
Містер Xcoder

1
@Jakube Добре, я буду пінг, коли я відмовлюся.
Містер Xcoder

1
OsmLабоOsmR
Якубе

1
@Jakube О, це дуже розумно! Неявний аргумент d, а потім карти dза діапазоном ... геніальність!
Erik the Outgolfer

8

CJam (9 байт)

q~_]ze~mR

Інтернет демо . Це повна програма, яка приймає введення у форматі масиву CJam на stdin та друкує вибраний елемент для stdout.

Розсічення

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

1
Настільки потужний гольф для такого простого завдання.
Erik the Outgolfer

7

Perl 6 , 20 байт

Збережено 1 байт завдяки @Brad Gilbert b2gills.

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

Спробуйте в Інтернеті!

Для цього потрібно 1 аргумент списку. Ми копіюємо 2 копії цього списку за допомогою xxоператора. Отже, з @_ Zxx@_, ми отримуємо список, в якому елементі xпредставлені xрази. Потім він примусовий Bag, що представляє собою колекцію, яка зберігає предмети разом із тим, скільки разів вони з’являються у колекції. Нарешті, ми вибираємо з цієї колекції випадковий елемент pick, який враховує підрахунки та робить The Right Thing ™.


Це можна скоротити до{bag(@_ Z=>@_).pick}
Бред Гілберт b2gills

@ BradGilbertb2gills, на жаль, це не працює. Це робить сумку з пар (так що не було б "1" один раз, "2" двічі і т.д., але "1 => 1" один раз, "2 => 2" також один раз і т. Д. - не те, що я хочу) . Це тому, що композитори не є примусовими, як це пояснено в цьому календарі адвентів .
Раміллі

@ 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().
Айб4бту

@ Ayb4btu Без for(;;)циклу це потребує другого (ніколи не досягнутого) оператора return після того, for(int i:a)...щоб задовольнити компілятор - що було б на 3 байти довше.
Невай

Ну, звичайно, ваш for(int i:a)як foreachу C #. У мене була така ж проблема, але я просто використовував цю, forщо постійно циклічно. Ваша нова відповідь мене заінтригує, я можу спробувати заграти деякі ваші ідеї.
Айб4бту

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

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них, які витягнуть один із елементів з (псевдо) рівною ймовірністю. Оскільки, наприклад, для@(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;

Подяка

11 байтів збережено завдяки Неваю, чия реалізація випадкових чисел була набагато більш короткою (а також intзамість а double).

Degolfed

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

Пояснення

Отримайте випадкове число, rміж 0 і сумою елементів. Потім при кожній ітерації віднімаємо поточний елемент від r. Якщо rменше 0, то поверніть цей елемент. Ідея полягає в тому, що для більших чисел в масиві є більші частини випадкового числа.


94 байти:a=>{int i=-1,r=new Random().Next(a.Sum());for(;r>=0;)r-=a[++i];return a[i];}
Невай

2

Japt , 7 байт

ËÆD
c ö

Перевірте це тут


Пояснення

Неявне введення масиву U.

Ë

Показуйте масив, що проходить кожен елемент, через функцію, де Dзнаходиться поточний елемент.

ÆD

Створіть масив довжини Dі заповніть його D.

c

Згладити.

ö

Отримайте випадковий елемент.



1

Perl, 31 байт

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

Це передбачає, що вхід є аргументами командного рядка. Зверніть увагу, що якщо великі цифри можуть втратити пам'ять




1

Вугілля деревне , 12 байт

F⪪θ;FIι⊞υι‽υ

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Оскільки Деревне вугілля намагається бути надто розумним, мені доведеться використовувати вхід для матриці, розділену крапкою з комою. Пояснення:

  θ             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 байт

-7 байт завдяки @Justin Mariner

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 +, ви можете скористатися: [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+ ))і подзвонити зinput::[].find(...)
Downgoat

1

Haskell , 78 77 байт

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

Спробуйте в Інтернеті! Приклад використання: f [1,99]ймовірно, врожайність 99.

Пояснення:

  • fприймає список цілих чисел lі повертає довільно вибране ціле число як IO Int.
  • l>>= \n->n<$[1..n]будує список з кожним елементом, nповтореним nразів.
  • randomRIO(0,sum l-1) виходить ціле число в діапазоні від 0 до довжини списку повторюваних елементів, що є точно сумою всіх елементів, мінус один, щоб уникнути не пов'язаного виключення.

Бонус: 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);}

-1 байт завдяки @Nevay .

Використовує аналогічний підхід, як і відповідь Jelly @ErikTheOutgolfer , додавши nрази пунктn до списку пункт, а потім вибравши його випадковим чином із цього списку.

Пояснення:

Спробуйте тут.

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 Дякую! Переміщення списку після кожної ітерації є досить неефективним, але що ми дбаємо про ефективність, попередження та таке, коли ми можемо позбутися ще одного додаткового байта. ; p
Кевін Круїссен


1

GNU APL 1.2, 26 23 байти; 1,7 21 19 байт

Підхід, натхненний Еліком Відповідь Желтої . Покладається на ⎕IO0, а не на 1, що є типовим для APL GNU (начебто +5 байт для ⎕IO←0).

-3, -2 байти завдяки @ Zacharý

форма функції

∇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

перетворює свій аргумент у список. За допомогою оператора transpose ( ) ми отримали вектор, що містить 3 вектори. Enlist ( ) перетворює його в єдиний вектор, що містить усі елементи.

S←...присвоює цей новий вектор вектору S. ⍴Sдає нам довжину цього списку. ?є випадковим оператором, тому ?⍴Sдає нам випадкове число між 0 і довжиною списку (виключно) (саме тому він покладається на ⎕IO0, інакше - від 1 до довжини включно). S[...]повертає елемент за заданим індексом.


Вам це не потрібно Q, оскільки ви ніколи не використовуєте його. І IIRC ви можете видалити новий рядок перед дель (маленька річ трикутника, що позначає кінець функції)
Zacharý

Нічого собі, я ніколи не з'являвся, <IO> <IO>⍉що головна діагональ була навіть річчю!
Zacharý

@ Zacharý Правильно, дякую. Щиро кажучи, я навіть не знав про транспозицію, поки не спробував цього завдання. Знайдено його тут
Arc676,

О, існує набагато кращий безкоштовний APL, ніж GNU, це називається ngn APL. Це насправді досить круто! ( ngn.github.io/apl/web , але він не має tradfn)
Zacharý

@ Zacharý У мене це теж :) На жаль, функція транспонування не працює (або я щось пропустив). Я буду тестувати його знову, коли я краще розумію, як це працює.
Arc676

1

MATLAB, 30 байт

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

Це передбачає MATLAB R2015a або новішої версії та встановлений набір інструментів статистики та машинного навчання.

Дивіться пояснення нижче щодо repelemвикористання. Відмінність цього коротшого та нижчого полягає в тому, що панель інструментів S&ML включає в себе функцію, datasampleяка може бути використана для випадкового взяття одного або декількох елементів з масиву (з однаковою ймовірністю), що дозволяє використовувати анонімну функцію, знімаючи input/dispдзвінки.

MATLAB, 49 байт

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

Цей код передбачає, що MATLAB R2015a або новіший використовується таким чином, коли repelemфункція була введена.repelemце функція, яка приймає два параметри, перший - це масив чисел, які потрібно реплікувати, а другий - це масив, у скільки разів повинен відповідати відповідний елемент. По суті, функція виконує декодування довжини пробігу, надаючи число та довжину виконання.

Надаючи однаковий вхід для обох входів, 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], 1буде мати 1/6 шанс, 2матиме 2/6 шанс , і 3буде мати 3/6 шанс.


Як зауваження, оскільки repelemще не доступно для Octave, я не можу надати TIO-посилання. Крім того , оскільки Октав не може бути використаний там великий штраф характер , як input()і disp()потрібно використовувати в якості анонімної функції не представляється можливим. Якщо Octave підтримується repelem, можна використовувати наступне:

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

Це врятувало б 16 байт, але цього не було.


Дійсно оцініть пояснення, дякую!
Ян Х.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.