Skip to content

Commit 9318f74

Browse files
committed
Add reduce to Enum.Iterator protocol
1 parent 26640e3 commit 9318f74

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

lib/elixir/lib/enum.ex

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ defprotocol Enum.Iterator do
1616

1717
@only [List, Record, Function]
1818

19+
def reduce(collection, acc, fun)
20+
1921
@doc """
2022
This function must return a tuple of the form `{ iter, step }` where
2123
`iter` is a function that yields successive values from the collection
@@ -1935,6 +1937,14 @@ defmodule Enum do
19351937
end
19361938

19371939
defimpl Enum.Iterator, for: List do
1940+
def reduce([h|t], acc, fun) do
1941+
reduce(t, fun.(h, acc), fun)
1942+
end
1943+
1944+
def reduce([], acc, _fun) do
1945+
acc
1946+
end
1947+
19381948
def iterator(list), do: list
19391949

19401950
def member?([], _), do: false
@@ -1944,6 +1954,10 @@ defimpl Enum.Iterator, for: List do
19441954
end
19451955

19461956
defimpl Enum.Iterator, for: Function do
1957+
def reduce(function, acc, fun) do
1958+
function.(acc, fun)
1959+
end
1960+
19471961
def iterator(function) do
19481962
{ iterator, first } = function.()
19491963
{ iterator, iterator.(first) }

lib/elixir/lib/hash_dict.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,14 @@ defmodule HashDict do
333333
drop(delete(dict, key), keys)
334334
end
335335

336+
def reduce(ordered(bucket: bucket), acc, fun) do
337+
:lists.foldl(fun, acc, bucket)
338+
end
339+
340+
def reduce(trie() = dict, acc, fun) do
341+
dict_fold(dict, acc, fun)
342+
end
343+
336344
## Dict-wide functions
337345

338346
defp dict_get(ordered(bucket: bucket), key) do
@@ -579,6 +587,7 @@ defmodule HashDict do
579587
end
580588

581589
defimpl Enum.Iterator, for: HashDict do
590+
def reduce(dict, acc, fun), do: HashDict.reduce(dict, acc, fun)
582591
def iterator(dict), do: HashDict.to_list(dict)
583592
def member?(dict, { k, v }), do: match?({ :ok, ^v }, HashDict.fetch(dict, k))
584593
def member?(_dict, _), do: false

lib/elixir/lib/range.ex

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ defrecord Range, [:first, :last] do
55
end
66

77
defprotocol Range.Iterator do
8+
def reduce(first, range, acc, fun)
9+
810
@doc """
911
How to iterate the range, receives the first
1012
and range as arguments. It needs to return a
@@ -21,6 +23,10 @@ defprotocol Range.Iterator do
2123
end
2224

2325
defimpl Enum.Iterator, for: Range do
26+
def reduce(Range[first: first] = range, acc, fun) do
27+
Range.Iterator.reduce(first, range, acc, fun)
28+
end
29+
2430
def iterator(Range[first: first] = range) do
2531
iterator = Range.Iterator.iterator(first, range)
2632
{ iterator, iterator.(first) }
@@ -36,6 +42,31 @@ defimpl Enum.Iterator, for: Range do
3642
end
3743

3844
defimpl Range.Iterator, for: Number do
45+
def reduce(first, Range[last: last], acc, fun) when is_integer(first) and is_integer(last) do
46+
reducer = if last >= first do
47+
fn(acc, fun) -> do_reducer_up(first, last, acc, fun) end
48+
else
49+
fn(acc, fun) -> do_reducer_down(first, last, acc, fun) end
50+
end
51+
Enum.Iterator.Function.reduce(reducer, acc, fun)
52+
end
53+
54+
defp do_reducer_up(counter, last, acc, fun) do
55+
if counter > last do
56+
acc
57+
else
58+
do_reducer_up(counter + 1, last, fun.(counter, acc), fun)
59+
end
60+
end
61+
62+
defp do_reducer_down(counter, last, acc, fun) do
63+
if counter < last do
64+
acc
65+
else
66+
do_reducer_down(counter - 1, last, fun.(counter, acc), fun)
67+
end
68+
end
69+
3970
def iterator(first, Range[last: last]) when is_integer(first) and is_integer(last) and last >= first do
4071
fn(current) ->
4172
if current > last, do: :stop, else: { current, current + 1 }

0 commit comments

Comments
 (0)