# Weight-based random sampling

**URL:** <https://forum.elixirforum.com/t/weight-based-random-sampling/23345>\
**Category:** Questions\
**Tags:** functional-programming\
**Created:** [June 23, 2019, 3:54pm UTC](https://forum.elixirforum.com/t/weight-based-random-sampling/23345 "2019-06-23T15:54:06Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![peerreynders](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/peerreynders/32/5826_2.png) [@peerreynders](https://forum.elixirforum.com/u/peerreynders)\
**Post date:** [June 23, 2019, 6:35pm UTC](https://forum.elixirforum.com/t/weight-based-random-sampling/23345/4 "2019-06-23T18:35:48Z")

</div>

So

```elixir
defmodule Demo do
  def weight_based_choice(items) do
    value =
      items
      |> Enum.reduce(0, &acc_weight/2)
      |> :rand.uniform()

    select_item(items, value)
  end

  # base cases
  defp select_item([{name, _}], _),
    do: name

  defp select_item([{name, weight} | _], index) when weight >= index,
    do: name

  # recursive case
  defp select_item([{_, weight} | tail], index),
    do: select_item(tail, index - weight)

  defp acc_weight({_, weight}, total),
    do: total + weight

end

items = [apples: 10, oranges: 30, bananas: 60]

items
|> Demo.weight_based_choice()
|> inspect()
|> IO.puts()

```

or

```elixir
defmodule Demo do
  def weight_based_choice(items) do
    marker =
      items
      |> Enum.reduce(0, &acc_weight/2)
      |> :rand.uniform()

    Enum.reduce_while(items, marker, &item_below_marker/2)
  end

  defp item_below_marker({_name, weight}, acc) when weight < acc,
    do: {:cont, acc - weight}

  defp item_below_marker({name, _weight}, _acc),
   do: {:halt, name}

  defp acc_weight({_, weight}, total),
    do: total + weight

end

items = [apples: 10, oranges: 30, bananas: 60]

items
|> Demo.weight_based_choice()
|> inspect()
|> IO.puts()

```

> While also making use of `Enum.reduce/3`

People tend to have familiarity with `reduce` from other languages - when learning I feel that resorting to `Enum` immediately is like heading straight for the power-tools even for the smallest job. To a certain degree choosing reduce when a simple recursive function will do feels a bit like “premature pessimization” especially as recursion is how iteration is accomplished in Elixir/Erlang - but I know I’m in the minority there.

---

_[View the full topic](https://forum.elixirforum.com/t/weight-based-random-sampling/23345)._
