Created
July 21, 2016 14:15
-
-
Save aaronjensen/d4cd40347a916dd36c8239afecf64a7d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defprotocol Enumerable do | |
require Stream.Reducers, as: R | |
defmacrop skip(acc) do | |
acc | |
end | |
defmacrop next(_, entry, acc) do | |
quote do: [unquote(entry) | unquote(acc)] | |
end | |
defmacrop acc(h, n, _) do | |
quote do: {unquote(h), unquote(n)} | |
end | |
defmacrop next_with_acc(f, entry, h, n, _) do | |
quote do | |
{[unquote(entry) | unquote(h)], unquote(n)} | |
end | |
end | |
def all?(enumerable, fun \\ fn(x) -> x end) | |
def all?(enumerable, fun) when is_list(enumerable) and is_function(fun, 1) do | |
do_all?(enumerable, fun) | |
end | |
def all?(enumerable, fun) when is_function(fun, 1) do | |
Enumerable.reduce(enumerable, {:cont, true}, fn(entry, _) -> | |
if fun.(entry), do: {:cont, true}, else: {:halt, false} | |
end) |> elem(1) | |
end | |
def any?(enumerable, fun \\ fn(x) -> x end) | |
def any?(enumerable, fun) when is_list(enumerable) and is_function(fun, 1) do | |
do_any?(enumerable, fun) | |
end | |
def any?(enumerable, fun) when is_function(fun, 1) do | |
Enumerable.reduce(enumerable, {:cont, false}, fn(entry, _) -> | |
if fun.(entry), do: {:halt, true}, else: {:cont, false} | |
end) |> elem(1) | |
end | |
def at(enumerable, index, default \\ nil) do | |
case fetch(enumerable, index) do | |
{:ok, h} -> h | |
:error -> default | |
end | |
end | |
def chunk(enumerable, count, step, leftover \\ nil) | |
when is_integer(count) and count > 0 and is_integer(step) and step > 0 do | |
limit = :erlang.max(count, step) | |
{acc, {buffer, i}} = | |
reduce(enumerable, {[], {[], 0}}, R.chunk(count, step, limit)) | |
if is_nil(leftover) || i == 0 do | |
:lists.reverse(acc) | |
else | |
buffer = :lists.reverse(buffer, take(leftover, count - i)) | |
:lists.reverse([buffer | acc]) | |
end | |
end | |
@spec chunk_by(t, (element -> any)) :: [list] | |
def chunk_by(enumerable, fun) when is_function(fun, 1) do | |
{acc, res} = reduce(enumerable, {[], nil}, R.chunk_by(fun)) | |
case res do | |
{buffer, _} -> | |
:lists.reverse([:lists.reverse(buffer) | acc]) | |
nil -> | |
[] | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment