从列表中获取随机元素

She*_*yar 29 elixir

我基本上都在寻找相当于Ruby的Elixir Array#sample.可以让我这样做的东西:

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

sample(list)
#=> 4

sample(list, 3)
#=> [6, 2, 5]
Run Code Online (Sandbox Code Playgroud)

我也没有在Elixir List Docs中找到任何内容.

She*_*yar 52

更新的答案

正如JoséValim在他的回答Elixir 1.1所说,你现在可以使用这些方法从列表中获取随机元素:

例:

Enum.random(list)                         #=> 4

Enum.take_random(list, 3)                 #=> [3, 9, 1]
Enum.take_random(list, 1)                 #=> [7]
Run Code Online (Sandbox Code Playgroud)

记得先打个电话:random.seed(:erlang.now)!


原始答案

我仍然无法找到一种"正确"和"神奇"的方式来做到这一点,但这是我能做到的最好的方法:

获取单个随机元素:

list |> Enum.shuffle |> hd
#=> 4
Run Code Online (Sandbox Code Playgroud)

注意:如果list为空,则会出现异常

获取多个随机元素:

list |> Enum.shuffle |> Enum.take(3)
#=> [7, 1, 5]
Run Code Online (Sandbox Code Playgroud)

  • 从Elixir 1.2开始,你不需要调用`:random.seed/1`,因为Elixir使用新的[`rand`](http://erlang.org/doc/man/rand.html)模块. (6认同)
  • 嗨,这是上述代码的作者.`Enum.random` /`take_random`最初被称为`sample`(就像在Ruby中一样)并且被合并到Elixir 1.1,后来被重命名.值得一提的是,使用[水库采样](https://en.wikipedia.org/wiki/Reservoir_sampling#Relation_to_Fisher-Yates_shuffle)算法的版本,它是关于可枚举大小的**O(n)**.这是我对Elixir标准库的第一次贡献 - 非常好的经验,人们在评论,讨论和整个工作流程方面都有很好的标准.我真的建议在那里做贡献. (2认同)

Jos*_*lim 11

Elixir 1.0中没有这样的功能,因此您需要自己实现它,如其他解决方案所述.但是,Enum.random/1随着Elixir v1.1的到来:https://hexdocs.pm/elixir/Enum.html#random/1


小智 5

另一种方法(仅对一个元素进行采样)是:

list |> Enum.at(:random.uniform(length(list)) - 1)
Run Code Online (Sandbox Code Playgroud)

如果您使用足够大的列表来改变整个列表可能会对性能产生影响,那么可能优于其他方法.

Gazler关于使用的评论:random.seed(:erlang.now)仍然适用.