Skip to content

Commit d101450

Browse files
committed
Optimize Enum.random/1 for ranges
1 parent 4e96f92 commit d101450

File tree

1 file changed

+20
-18
lines changed

1 file changed

+20
-18
lines changed

lib/elixir/lib/enum.ex

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2390,7 +2390,14 @@ defmodule Enum do
23902390
def random(enumerable) when is_list(enumerable) do
23912391
case length(enumerable) do
23922392
0 -> raise Enum.EmptyError
2393-
length -> enumerable |> drop_list(random_integer(0, length - 1)) |> hd()
2393+
length -> enumerable |> drop_list(random_count(length)) |> hd()
2394+
end
2395+
end
2396+
2397+
def random(first.._//step = range) do
2398+
case Range.size(range) do
2399+
0 -> raise Enum.EmptyError
2400+
size -> first + random_count(size) * step
23942401
end
23952402
end
23962403

@@ -2401,14 +2408,14 @@ defmodule Enum do
24012408
[]
24022409

24032410
{:ok, count, fun} when is_function(fun, 1) ->
2404-
slice_list(fun.(enumerable), random_integer(0, count - 1), 1, 1)
2411+
slice_list(fun.(enumerable), random_count(count), 1, 1)
24052412

24062413
# TODO: Deprecate me in Elixir v1.18.
24072414
{:ok, count, fun} when is_function(fun, 2) ->
2408-
fun.(random_integer(0, count - 1), 1)
2415+
fun.(random_count(count), 1)
24092416

24102417
{:ok, count, fun} when is_function(fun, 3) ->
2411-
fun.(random_integer(0, count - 1), 1, 1)
2418+
fun.(random_count(count), 1, 1)
24122419

24132420
{:error, _} ->
24142421
take_random(enumerable, 1)
@@ -2420,6 +2427,10 @@ defmodule Enum do
24202427
end
24212428
end
24222429

2430+
defp random_count(count) do
2431+
:rand.uniform(count) - 1
2432+
end
2433+
24232434
@doc """
24242435
Invokes `fun` for each element in the `enumerable` with the
24252436
accumulator.
@@ -3609,7 +3620,7 @@ defmodule Enum do
36093620
sample = Tuple.duplicate(nil, count)
36103621

36113622
reducer = fn elem, {idx, sample} ->
3612-
jdx = random_integer(0, idx)
3623+
jdx = random_index(idx)
36133624

36143625
cond do
36153626
idx < count ->
@@ -3630,7 +3641,7 @@ defmodule Enum do
36303641

36313642
def take_random(enumerable, count) when is_integer(count) and count >= 0 do
36323643
reducer = fn elem, {idx, sample} ->
3633-
jdx = random_integer(0, idx)
3644+
jdx = random_index(idx)
36343645

36353646
cond do
36363647
idx < count ->
@@ -3666,6 +3677,9 @@ defmodule Enum do
36663677

36673678
defp take_random_list_one([], current, _), do: [current]
36683679

3680+
defp random_index(0), do: 0
3681+
defp random_index(idx), do: :rand.uniform(idx + 1) - 1
3682+
36693683
@doc """
36703684
Takes the elements from the beginning of the `enumerable` while `fun` returns
36713685
a truthy value.
@@ -4149,18 +4163,6 @@ defmodule Enum do
41494163
end)
41504164
end
41514165

4152-
defp random_integer(limit, limit) when is_integer(limit) do
4153-
limit
4154-
end
4155-
4156-
defp random_integer(lower_limit, upper_limit) when upper_limit < lower_limit do
4157-
random_integer(upper_limit, lower_limit)
4158-
end
4159-
4160-
defp random_integer(lower_limit, upper_limit) do
4161-
lower_limit + :rand.uniform(upper_limit - lower_limit + 1) - 1
4162-
end
4163-
41644166
## Implementations
41654167

41664168
## all?/1

0 commit comments

Comments
 (0)