Произвольно выбрать из массива


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
Можете ли вы объяснить, что делает ваш код, пожалуйста? :)
Ян Х.

1
@IanH. Это действительно простой алгоритм, повторять каждый элемент сам, а затем выбирать случайным образом.
Эрик 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]].
       - ... Кредит идет на Якубе за это!
 с - Флаттен.
O - Случайный элемент ^. Отображать неявно.

# 2

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

  m - Карта над входом.
    ] - текущий элемент, d, обернутый; [D].
   * - повторяется д раз.
 с - Флаттен.
O - Случайный Элемент. Неявно выведите результат.

1
Я могу сделать это в 4. Должен ли я испортить это, или вы хотите найти это самостоятельно?
Якуб

2
@Jakube Подождите немного. Хочу посмотреть, смогу ли я это сделать. Является ли это , что очевидно?
г-н Xcoder

1
@Jakube Хорошо, я буду пинговать, когда сдаюсь.
г-н Xcoder

1
OsmLилиOsmR
Якуб

1
@ Якуб О, это очень умно! Неявный аргумент d, затем карты dв диапазоне ... гений!
Эрик Outgolfer

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
Такой мощный гольф для такой простой задачи.
Эрик 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" также один раз и т. Д. - не то, что я хочу) , Это потому, что композиторы не являются коучерами, как объясняется в этом календаре .
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)...чтобы удовлетворить компилятор - который был бы на 3 байта длиннее.
Невай

Ах, конечно, ваш for(int i:a)как foreachв C #. У меня была та же самая проблема, но я просто использовал тот, 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 Я должен был проверить это больше, хороший улов.
Коул

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 байтов сохранено благодаря Nevay, чья реализация случайных чисел была намного более краткой (а также intвместо a 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ι⊞υι‽υ

Попробуйте онлайн! Ссылка на подробную версию кода. Так как 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 байта

-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 .

Использует тот же подход, что и @ErikTheOutgolfer 's Jelly answer , добавляя 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 байт

Подход, вдохновленный ответом желе Эрика Аутгольфера . Полагается, ⎕IOчто 0 вместо 1, что является значением по умолчанию для GNU APL (вроде +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 и длиной списка (исключая) (вот почему он полагается ⎕IOравным 0; в противном случае он находится между 1 и длиной, включительно). S[...]возвращает элемент по указанному индексу.


Вам не нужно Q, так как вы никогда не используете его. И IIRC вы можете удалить символ новой строки перед del (маленький треугольник, отмечающий конец функции.)
Zacharý

Ничего себе, я никогда не узнал, <IO> <IO>⍉чтобы главная диагональ была даже вещь!
Захари

@ Zacharý Правильно, спасибо. Честно говоря, я даже не знал о транспонировании, пока не попробовал эту задачу. Нашел это здесь
Arc676

О, существует гораздо лучший бесплатный APL, чем GNU, он называется ngn APL. Это на самом деле очень круто! ( ngn.github.io/apl/web , но не имеет tradfn)
Захари

@ 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.