Skip to content

Commit d9a8110

Browse files
committed
Optimize Enum.into and Map.new
1 parent 8fca53a commit d9a8110

File tree

3 files changed

+46
-27
lines changed

3 files changed

+46
-27
lines changed

lib/elixir/lib/enum.ex

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,28 +1421,35 @@ defmodule Enum do
14211421
into_protocol(enumerable, collectable)
14221422
end
14231423

1424-
def into(%{} = enumerable, %{} = collectable) do
1425-
Map.merge(collectable, enumerable)
1426-
end
1427-
1428-
def into(enumerable, %{} = collectable) when is_list(enumerable) do
1429-
Map.merge(collectable, :maps.from_list(enumerable))
1430-
end
1431-
14321424
def into(enumerable, %{} = collectable) do
1433-
reduce(enumerable, collectable, fn {key, val}, acc ->
1434-
Map.put(acc, key, val)
1435-
end)
1425+
if map_size(collectable) == 0 do
1426+
into_map(enumerable)
1427+
else
1428+
into_map(enumerable, collectable)
1429+
end
14361430
end
14371431

14381432
def into(enumerable, collectable) do
14391433
into_protocol(enumerable, collectable)
14401434
end
14411435

1436+
defp into_map(%{} = enumerable), do: enumerable
1437+
defp into_map(enumerable) when is_list(enumerable), do: :maps.from_list(enumerable)
1438+
defp into_map(enumerable), do: enumerable |> Enum.to_list() |> :maps.from_list(enumerable)
1439+
1440+
defp into_map(%{} = enumerable, collectable),
1441+
do: Map.merge(collectable, enumerable)
1442+
1443+
defp into_map(enumerable, collectable) when is_list(enumerable),
1444+
do: Map.merge(collectable, :maps.from_list(enumerable))
1445+
1446+
defp into_map(enumerable, collectable),
1447+
do: Enum.reduce(enumerable, collectable, fn {key, val}, acc -> Map.put(acc, key, val) end)
1448+
14421449
defp into_protocol(enumerable, collectable) do
14431450
{initial, fun} = Collectable.into(collectable)
14441451

1445-
into(enumerable, initial, fun, fn entry, acc ->
1452+
into_protocol(enumerable, initial, fun, fn entry, acc ->
14461453
fun.(acc, {:cont, entry})
14471454
end)
14481455
end
@@ -1461,20 +1468,42 @@ defmodule Enum do
14611468
14621469
"""
14631470
@spec into(Enumerable.t(), Collectable.t(), (term -> term)) :: Collectable.t()
1464-
14651471
def into(enumerable, collectable, transform) when is_list(collectable) do
14661472
collectable ++ map(enumerable, transform)
14671473
end
14681474

1475+
def into(%_{} = enumerable, collectable, transform) do
1476+
into_protocol(enumerable, collectable, transform)
1477+
end
1478+
1479+
def into(enumerable, %_{} = collectable, transform) do
1480+
into_protocol(enumerable, collectable, transform)
1481+
end
1482+
1483+
def into(enumerable, %{} = collectable, transform) do
1484+
if map_size(collectable) == 0 do
1485+
enumerable |> Enum.map(transform) |> :maps.from_list()
1486+
else
1487+
Enum.reduce(enumerable, collectable, fn entry, acc ->
1488+
{key, val} = transform.(entry)
1489+
Map.put(acc, key, val)
1490+
end)
1491+
end
1492+
end
1493+
14691494
def into(enumerable, collectable, transform) do
1495+
into_protocol(enumerable, collectable, transform)
1496+
end
1497+
1498+
defp into_protocol(enumerable, collectable, transform) do
14701499
{initial, fun} = Collectable.into(collectable)
14711500

1472-
into(enumerable, initial, fun, fn entry, acc ->
1501+
into_protocol(enumerable, initial, fun, fn entry, acc ->
14731502
fun.(acc, {:cont, transform.(entry)})
14741503
end)
14751504
end
14761505

1477-
defp into(enumerable, initial, fun, callback) do
1506+
defp into_protocol(enumerable, initial, fun, callback) do
14781507
try do
14791508
reduce(enumerable, initial, callback)
14801509
catch

lib/elixir/lib/map.ex

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -216,20 +216,10 @@ defmodule Map do
216216
@spec new(Enumerable.t(), (term -> {key, value})) :: map
217217
def new(enumerable, transform) when is_function(transform, 1) do
218218
enumerable
219-
|> Enum.to_list()
220-
|> new_transform(transform, [])
221-
end
222-
223-
defp new_transform([], _fun, acc) do
224-
acc
225-
|> :lists.reverse()
219+
|> Enum.map(transform)
226220
|> :maps.from_list()
227221
end
228222

229-
defp new_transform([element | rest], fun, acc) do
230-
new_transform(rest, fun, [fun.(element) | acc])
231-
end
232-
233223
@doc """
234224
Returns whether the given `key` exists in the given `map`.
235225

lib/elixir/test/elixir/enum_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ defmodule EnumTest do
405405
assert Enum.into([1, 2, 3], [], fn x -> x * 2 end) == [2, 4, 6]
406406
assert Enum.into([1, 2, 3], "numbers: ", &to_string/1) == "numbers: 123"
407407

408-
assert_raise FunctionClauseError, fn ->
408+
assert_raise MatchError, fn ->
409409
Enum.into([2, 3], %{a: 1}, & &1)
410410
end
411411
end

0 commit comments

Comments
 (0)