Skip to content

Instantly share code, notes, and snippets.

@aaronjensen
Created July 21, 2016 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aaronjensen/d4cd40347a916dd36c8239afecf64a7d to your computer and use it in GitHub Desktop.
Save aaronjensen/d4cd40347a916dd36c8239afecf64a7d to your computer and use it in GitHub Desktop.
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