Получить случайный элемент (ы) из списка

17

В основном я ищу эквивалент Elixir для Ruby Array#sample . Что-то, что позволит мне сделать это:

list = [1,2,3,4,5,6,7]

sample(list)
#=> 4

sample(list, 3)
#=> [6, 2, 5]

Я ничего не нашел в Документах списков эликсиров .

    
задан Sheharyar 04.07.2015 в 14:29
источник
  • Я понимаю, что вы просите, но мне любопытно, почему такая функция будет частью стандартной библиотеки Ruby. –  Onorio Catenacci 06.07.2015 в 14:13

4 ответа

32

Обновленный ответ

Как сказал Хосе Валим в своем ответе , в Elixir 1.1 и выше, теперь вы можете использовать эти методы для получения случайных элементов из списка:

  • Enum.random/1 - для получения одного случайного элемента
  • Enum.take_random/2 - для получения нескольких случайных элементов

Пример:

Enum.random(list)                         #=> 4

Enum.take_random(list, 3)                 #=> [3, 9, 1]
Enum.take_random(list, 1)                 #=> [7]

Не забудьте сначала сначала вызвать :random.seed(:erlang.now) !

Оригинальный ответ

Я все еще не могу найти «правильный» и «магический» способ сделать это, но это лучшее, что я мог бы придумать:

Для получения одного случайного элемента:

list |> Enum.shuffle |> hd
#=> 4

Примечание. Это дает исключение, если list пуст

Для получения нескольких случайных элементов:

list |> Enum.shuffle |> Enum.take(3)
#=> [7, 1, 5]
    
ответ дан Sheharyar 04.07.2015 в 14:45
  • Если вы получите предупреждения типа «warning: erlang: now / 0: Устаревший BIF», см. главу «Временная коррекция в Erlang» главы Руководства пользователя ERTS для получения дополнительной информации. », вместо этого семя: случайное. семян (: os.timestamp) –  Henrik N 03.12.2015 в 22:24
  • Начиная с Elixir 1.2 вам не нужно вызывать: random.seed / 1, поскольку Elixir для этого использует новый модуль rand. –  Adam Lindberg 08.06.2016 в 16:31
  • Привет, это автор упомянутого кода. Enum.random / take_random изначально назывался sample (как в Ruby) и был объединен с Elixir 1.1, позже переименованный. Стоит упомянуть, что это O (n) в отношении размера перечислимого, используя версию алгоритма выборки коллектора. Это был мой первый вклад в стандартную библиотеку Elixir - очень хороший опыт, у ребят есть отличные стандарты в отношении обзоров, обсуждений и всего рабочего процесса. Я действительно рекомендую участвовать там. –  Wojciech Kaczmarek 23.10.2017 в 23:57
7

В Elixir 1.0 такой функции нет, поэтому вам нужно реализовать ее самостоятельно, как упомянуто другими решениями. Тем не менее, Enum.random/1 идет с Elixir v1.1: Ссылка     

ответ дан José Valim 05.07.2015 в 13:25
5

Другой способ (для выборки только одного элемента):

list |> Enum.at(:random.uniform(length(list)) - 1)

Возможно, предпочтительнее другого метода, если вы работаете с достаточно большими списками, которые могут повлиять на перетасовку всего списка.

комментарий Gazler об использовании :random.seed(:erlang.now) применяется.

    
ответ дан Simon Woolf 05.07.2015 в 00:54
1

Если вы используете более новую версию Elixir, есть функция Enum.take_random/2 , которая была добавлена ​​в Elixir v1.1.

Из документа Elixir v1.1 :

  

Принимает случайные элементы из коллекции.

     

Обратите внимание, что эта функция пересечет всю коллекцию, чтобы получить случайный подсписк коллекции. Если вам требуется случайное число между двумя целыми числами, лучшим вариантом является использование: случайного модуля.

Итак, отвечая на вопрос, взятие нескольких элементов из списка будет выглядеть так:

list = [1,2,3,4,5,6,7]
Enum.take_random(list, 3)
#=> [2, 4, 1]

Или, для одного элемента:

list = [1,2,3,4,5,6,7]
Enum.take_random(list, 1)
#=> [1]
    
ответ дан Ilija Eftimov 10.10.2015 в 16:09