Skip to content

Commit 5e6602e

Browse files
committed
ft: add Enum.sum/2
The behaviour of new function is similar to `map/2` followed by `sum/1`. This behaves similarly to: - `Enum.all?/2` - `Enum.any?/2` - `Enum.count/2` - All `*_by/2` functions This should simplify a lot of cases when we want to sum values stored in nested manner like summing values in list of tuples, list of maps, or even in maps itself.
1 parent e414cc0 commit 5e6602e

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

lib/elixir/lib/enum.ex

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3070,6 +3070,31 @@ defmodule Enum do
30703070
reduce(enumerable, 0, &+/2)
30713071
end
30723072

3073+
@doc """
3074+
Returns the sum of values returned by mapper.
3075+
3076+
Raises `ArithmeticError` if `mapper` returns a non-numeric value.
3077+
3078+
## Examples
3079+
3080+
iex> Enum.sum([1, 2, 3], &(&1 * 2))
3081+
12
3082+
3083+
iex> Enum.sum(1..10, &(&1 / 2))
3084+
27.5
3085+
3086+
iex> Enum.sum(1..10//2, &(&1**2))
3087+
165
3088+
3089+
iex> Enum.sum([{1}, {2}], &elem(&1, 0))
3090+
3
3091+
3092+
"""
3093+
@spec sum(t, (element -> number)) :: number
3094+
def sum(enumerable, mapper) do
3095+
reduce(enumerable, 0, fn elem, acc -> mapper.(elem) + acc end)
3096+
end
3097+
30733098
@doc """
30743099
Returns the product of all elements.
30753100

lib/elixir/test/elixir/enum_test.exs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,44 @@ defmodule EnumTest do
10811081
end
10821082
end
10831083

1084+
describe "sum/2" do
1085+
test "with identity function behaves exactly the same as sum/1" do
1086+
id = &Function.identity/1
1087+
1088+
assert Enum.sum([], id) == 0
1089+
assert Enum.sum([1], id) == 1
1090+
assert Enum.sum([1, 2, 3], id) == 6
1091+
assert Enum.sum([1.1, 2.2, 3.3], id) == 6.6
1092+
assert Enum.sum([-3, -2, -1, 0, 1, 2, 3], id) == 0
1093+
assert Enum.sum(42..42, id) == 42
1094+
assert Enum.sum(11..17, id) == 98
1095+
assert Enum.sum(17..11, id) == 98
1096+
assert Enum.sum(11..-17, id) == Enum.sum(-17..11, id)
1097+
1098+
assert_raise ArithmeticError, fn ->
1099+
Enum.sum([{}], id)
1100+
end
1101+
1102+
assert_raise ArithmeticError, fn ->
1103+
Enum.sum([1, {}], id)
1104+
end
1105+
end
1106+
1107+
test "with mapping" do
1108+
assert Enum.sum([], & &1.foo) == 0
1109+
assert Enum.sum([%{foo: 1}], & &1.foo) == 1
1110+
assert Enum.sum([%{foo: 1, bar: 2}], & &1.foo) == 1
1111+
1112+
assert Enum.sum([1], &(&1 * 2)) == 2
1113+
assert Enum.sum([1, 2, 3], &(&1 * 2)) == 12
1114+
assert Enum.sum([1.1, 2.2, 3.3], &(&1 * 2)) == 13.2
1115+
1116+
assert_raise ArithmeticError, fn ->
1117+
Enum.sum([%{foo: nil}], & &1.foo) == 1
1118+
end
1119+
end
1120+
end
1121+
10841122
test "product/1" do
10851123
assert Enum.product([]) == 1
10861124
assert Enum.product([1]) == 1

0 commit comments

Comments
 (0)