diff options
Diffstat (limited to 'lib/elixir')
-rw-r--r-- | lib/elixir/lib/enum.ex | 45 | ||||
-rw-r--r-- | lib/elixir/lib/stream.ex | 6 | ||||
-rw-r--r-- | lib/elixir/test/elixir/enum_test.exs | 119 | ||||
-rw-r--r-- | lib/elixir/test/elixir/stream_test.exs | 2 |
4 files changed, 63 insertions, 109 deletions
diff --git a/lib/elixir/lib/enum.ex b/lib/elixir/lib/enum.ex index 7cc751506..32a46d4fe 100644 --- a/lib/elixir/lib/enum.ex +++ b/lib/elixir/lib/enum.ex @@ -1647,13 +1647,9 @@ defmodule Enum do Raises `Enum.EmptyError` if `enumerable` is empty. - Notice that you need to explicitly call `:random.seed/1` and - set a seed value for the random algorithm. Otherwise, the - default seed will be set which will always return the same - result. For example, one could do the following to set a seed - dynamically: - - :random.seed(:os.timestamp) + This function uses Erlang's `:rand` module to calculate + the random value. Check its documentation for setting a + different random algorithm or a different seed. The implementation is based on the [reservoir sampling](https://en.wikipedia.org/wiki/Reservoir_sampling#Relation_to_Fisher-Yates_shuffle) @@ -1663,10 +1659,12 @@ defmodule Enum do ## Examples - iex> Enum.random([1, 2, 3]) - 1 + # Although not necessary, let's seed the random algorithm + iex> :rand.seed(:exsplus, {1, 2, 3}) iex> Enum.random([1, 2, 3]) 2 + iex> Enum.random([1, 2, 3]) + 1 """ @spec random(t) :: element | no_return @@ -1714,29 +1712,24 @@ defmodule Enum do @doc """ Returns a list with the elements of `enumerable` shuffled. - Notice that you need to explicitly call `:random.seed/1` and - set a seed value for the random algorithm. Otherwise, the - default seed will be set which will always return the same - result. For example, one could do the following to set a seed - dynamically: - - :random.seed(:os.timestamp) - - To see what happens if you don't do this, shuffle the same list - in two separate IEx sessions. The results will be the same. + This function uses Erlang's `:rand` module to calculate + the random value. Check its documentation for setting a + different random algorithm or a different seed. ## Examples + # Although not necessary, let's seed the random algorithm + iex> :rand.seed(:exsplus, {1, 2, 3}) iex> Enum.shuffle([1, 2, 3]) - [3, 2, 1] + [2, 1, 3] iex> Enum.shuffle([1, 2, 3]) - [3, 1, 2] + [2, 3, 1] """ @spec shuffle(t) :: list def shuffle(enumerable) do randomized = reduce(enumerable, [], fn x, acc -> - [{:random.uniform, x}|acc] + [{:rand.uniform, x}|acc] end) unwrap(:lists.keysort(1, randomized), []) end @@ -2148,10 +2141,12 @@ defmodule Enum do ## Examples + # Although not necessary, let's seed the random algorithm + iex> :rand.seed(:exsplus, {1, 2, 3}) iex> Enum.take_random(1..10, 2) - [1, 5] + [5, 8] iex> Enum.take_random(?a..?z, 5) - 'tfesm' + 'fhjni' """ @spec take_random(t, integer) :: list @@ -2386,7 +2381,7 @@ defmodule Enum do defp enum_to_string(entry), do: String.Chars.to_string(entry) defp random_index(n) do - :random.uniform(n + 1) - 1 + :rand.uniform(n + 1) - 1 end ## Implementations diff --git a/lib/elixir/lib/stream.ex b/lib/elixir/lib/stream.ex index ac9efcd87..7ccfa7ab5 100644 --- a/lib/elixir/lib/stream.ex +++ b/lib/elixir/lib/stream.ex @@ -1023,8 +1023,10 @@ defmodule Stream do ## Examples - iex> Stream.repeatedly(&:random.uniform/0) |> Enum.take(3) - [0.4435846174457203, 0.7230402056221108, 0.94581636451987] + # Although not necessary, let's seed the random algorithm + iex> :rand.seed(:exsplus, {1, 2, 3}) + iex> Stream.repeatedly(&:rand.uniform/0) |> Enum.take(3) + [0.40502929729990744, 0.45336720247823126, 0.04094511692041057] """ @spec repeatedly((() -> element)) :: Enumerable.t diff --git a/lib/elixir/test/elixir/enum_test.exs b/lib/elixir/test/elixir/enum_test.exs index f608801ad..1cc2bafba 100644 --- a/lib/elixir/test/elixir/enum_test.exs +++ b/lib/elixir/test/elixir/enum_test.exs @@ -304,16 +304,16 @@ defmodule EnumTest.List do # set a fixed seed so the test can be deterministic # please note the order of following assertions is important seed1 = {1406, 407414, 139258} - seed2 = {1406, 421106, 567597} - :random.seed(seed1) + seed2 = {1306, 421106, 567597} + :rand.seed(:exsplus, seed1) + assert Enum.random([1, 2]) == 1 + assert Enum.random([1, 2, 3]) == 1 + assert Enum.random([1, 2, 3, 4]) == 2 + assert Enum.random([1, 2, 3, 4, 5]) == 4 + :rand.seed(:exsplus, seed2) assert Enum.random([1, 2]) == 2 assert Enum.random([1, 2, 3]) == 2 - assert Enum.random([1, 2, 3, 4]) == 4 - assert Enum.random([1, 2, 3, 4, 5]) == 1 - :random.seed(seed2) - assert Enum.random([1, 2]) == 1 - assert Enum.random([1, 2, 3]) == 3 - assert Enum.random([1, 2, 3, 4]) == 1 + assert Enum.random([1, 2, 3, 4]) == 3 assert Enum.random([1, 2, 3, 4, 5]) == 5 end @@ -330,25 +330,21 @@ defmodule EnumTest.List do # please note the order of following assertions is important seed1 = {1406, 407414, 139258} seed2 = {1406, 421106, 567597} - :random.seed(seed1) - assert Enum.take_random([1, 2, 3, 4, 5], 1) == [2] - assert Enum.take_random([1, 2, 3, 4, 5], 2) == [4, 1] - assert Enum.take_random([1, 2, 3, 4, 5], 3) == [1, 3, 5] - assert Enum.take_random([1, 2, 3, 4, 5], 4) == [3, 5, 1, 2] - assert Enum.take_random([1, 2, 3, 4, 5], 5) == [1, 2, 5, 4, 3] - assert Enum.take_random([1, 2, 3, 4, 5], 6) == [2, 4, 5, 3, 1] - :random.seed(seed2) - assert Enum.take_random([1, 2, 3, 4, 5], 1) == [1] - assert Enum.take_random([1, 2, 3, 4, 5], 2) == [1, 5] - assert Enum.take_random([1, 2, 3, 4, 5], 3) == [5, 1, 3] - assert Enum.take_random([1, 2, 3, 4, 5], 4) == [4, 5, 2, 1] - assert Enum.take_random([1, 2, 3, 4, 5], 5) == [4, 3, 1, 5, 2] - assert Enum.take_random([1, 2, 3, 4, 5], 6) == [5, 2, 1, 4, 3] + :rand.seed(:exsplus, seed1) + assert Enum.take_random([1, 2, 3], 1) == [1] + assert Enum.take_random([1, 2, 3], 2) == [1, 3] + assert Enum.take_random([1, 2, 3], 3) == [2, 1, 3] + assert Enum.take_random([1, 2, 3], 4) == [3, 1, 2] + :rand.seed(:exsplus, seed2) + assert Enum.take_random([1, 2, 3], 1) == [3] + assert Enum.take_random([1, 2, 3], 2) == [1, 2] + assert Enum.take_random([1, 2, 3], 3) == [1, 2, 3] + assert Enum.take_random([1, 2, 3], 4) == [1, 2, 3] # assert that every item in the sample comes from the input list list = for _<-1..100, do: make_ref for x <- Enum.take_random(list, 50) do - assert Enum.find(list, &(&1 == x)) + assert x in list end end @@ -362,8 +358,8 @@ defmodule EnumTest.List do test "shuffle" do # set a fixed seed so the test can be deterministic - :random.seed(1374, 347975, 449264) - assert Enum.shuffle([1, 2, 3, 4, 5]) == [2, 4, 1, 5, 3] + :rand.seed(:exsplus, {1374, 347975, 449264}) + assert Enum.shuffle([1, 2, 3, 4, 5]) == [2, 1, 3, 5, 4] end test "sort" do @@ -935,25 +931,13 @@ defmodule EnumTest.Range do # set a fixed seed so the test can be deterministic # please note the order of following assertions is important seed1 = {1406, 407414, 139258} - seed2 = {1406, 421106, 567597} - :random.seed(seed1) + seed2 = {1306, 421106, 567597} + :rand.seed(:exsplus, seed1) + assert Enum.random(1..2) == 1 + assert Enum.random(1..3) == 1 + :rand.seed(:exsplus, seed2) assert Enum.random(1..2) == 2 assert Enum.random(1..3) == 2 - assert Enum.random(1..4) == 4 - assert Enum.random(1..5) == 1 - :random.seed(seed1) - assert Enum.random(?a..?z) == ?i - :random.seed(seed1) - assert Enum.random(?0..?9) == ?8 - :random.seed(seed2) - assert Enum.random(1..2) == 1 - assert Enum.random(1..3) == 3 - assert Enum.random(1..4) == 1 - assert Enum.random(1..5) == 5 - :random.seed(seed2) - assert Enum.random(?a..?z) == ?a - :random.seed(seed2) - assert Enum.random(?0..?9) == ?0 end test "take random" do @@ -967,43 +951,16 @@ defmodule EnumTest.Range do # please note the order of following assertions is important seed1 = {1406, 407414, 139258} seed2 = {1406, 421106, 567597} - :random.seed(seed1) - assert Enum.take_random(1..5, 1) == [2] - assert Enum.take_random(1..5, 2) == [4, 1] - assert Enum.take_random(1..5, 3) == [1, 3, 5] - assert Enum.take_random(1..5, 4) == [3, 5, 1, 2] - assert Enum.take_random(1..5, 5) == [1, 2, 5, 4, 3] - assert Enum.take_random(1..5, 6) == [2, 4, 5, 3, 1] - :random.seed(seed2) - assert Enum.take_random(1..5, 1) == [1] - assert Enum.take_random(1..5, 2) == [1, 5] - assert Enum.take_random(1..5, 3) == [5, 1, 3] - assert Enum.take_random(1..5, 4) == [4, 5, 2, 1] - assert Enum.take_random(1..5, 5) == [4, 3, 1, 5, 2] - assert Enum.take_random(1..5, 6) == [5, 2, 1, 4, 3] - - :random.seed(seed1) - assert Enum.take_random(1..200, 130) == [107, 168, 172, 88, 98, 89, 64, 104, 161, - 28, 128, 125, 30, 182, 194, 140, 198, 113, 191, 69, 126, 37, 115, 147, 193, 152, - 154, 145, 127, 99, 148, 52, 17, 63, 59, 54, 38, 80, 100, 188, 122, 19, 41, 108, - 26, 81, 10, 158, 195, 60, 95, 24, 117, 163, 141, 62, 116, 176, 156, 31, 73, 120, - 55, 76, 44, 174, 110, 25, 136, 166, 149, 83, 106, 159, 46, 138, 157, 187, 93, 131, - 180, 109, 162, 67, 22, 5, 170, 18, 143, 177, 146, 153, 34, 167, 137, 160, 175, 16, - 74, 1, 51, 134, 47, 35, 85, 75, 179, 61, 130, 151, 118, 129, 164, 42, 86, 48, 186, - 8, 192, 20, 90, 150, 178, 39, 92, 171, 56, 2, 200, 155] - - :random.seed(seed1) - assert Enum.take_random(?a..?z, 1) == 'i' - assert Enum.take_random(?a..?z, 2) == 'cm' - assert Enum.take_random(?a..?z, 3) == 'alp' - assert Enum.take_random(?a..?z, 4) == 'tzmd' - assert Enum.take_random(?a..?z, 5) == 'cuxvb' - :random.seed(seed2) - assert Enum.take_random(?a..?z, 1) == 'a' - assert Enum.take_random(?a..?z, 2) == 'wk' - assert Enum.take_random(?a..?z, 3) == 'ayj' - assert Enum.take_random(?a..?z, 4) == 'rbcm' - assert Enum.take_random(?a..?z, 5) == 'rhzju' + :rand.seed(:exsplus, seed1) + assert Enum.take_random(1..3, 1) == [1] + assert Enum.take_random(1..3, 2) == [1, 3] + assert Enum.take_random(1..3, 3) == [2, 1, 3] + assert Enum.take_random(1..3, 4) == [3, 1, 2] + :rand.seed(:exsplus, seed2) + assert Enum.take_random(1..3, 1) == [3] + assert Enum.take_random(1..3, 2) == [1, 2] + assert Enum.take_random(1..3, 3) == [1, 2, 3] + assert Enum.take_random(1..3, 4) == [1, 2, 3] end test "scan" do @@ -1013,8 +970,8 @@ defmodule EnumTest.Range do test "shuffle" do # set a fixed seed so the test can be deterministic - :random.seed(1374, 347975, 449264) - assert Enum.shuffle(1..5) == [2, 4, 1, 5, 3] + :rand.seed(:exsplus, {1374, 347975, 449264}) + assert Enum.shuffle(1..5) == [2, 1, 3, 5, 4] end test "slice" do diff --git a/lib/elixir/test/elixir/stream_test.exs b/lib/elixir/test/elixir/stream_test.exs index 361c788d3..cb2094c6a 100644 --- a/lib/elixir/test/elixir/stream_test.exs +++ b/lib/elixir/test/elixir/stream_test.exs @@ -478,7 +478,7 @@ defmodule StreamTest do test "repeatedly/1" do stream = Stream.repeatedly(fn -> 1 end) assert Enum.take(stream, 5) == [1, 1, 1, 1, 1] - stream = Stream.repeatedly(&:random.uniform/0) + stream = Stream.repeatedly(&:rand.uniform/0) [r1, r2] = Enum.take(stream, 2) assert r1 != r2 end |