diff options
author | Eric Entin <whoknew@gmail.com> | 2016-07-03 16:23:11 -0400 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2016-07-03 22:23:11 +0200 |
commit | 652c40875e0ed4528206a28a33047717b27324bd (patch) | |
tree | 27a1bac9df1c60f8e34b208fd1608bb8139eb630 | |
parent | db8836c08f11cd738b50b0b1d9d9b252fb52827b (diff) | |
download | elixir-652c40875e0ed4528206a28a33047717b27324bd.tar.gz |
Add Stream.uniq_by/2 and deprecate Stream.uniq/2 (#4934)
* Add Stream.uniq_by/2 and deprecate Stream.uniq/2
* Rename Stream.Reducers.uniq to Stream.Reducers.uniq_by
-rw-r--r-- | lib/elixir/lib/enum.ex | 3 | ||||
-rw-r--r-- | lib/elixir/lib/stream.ex | 38 | ||||
-rw-r--r-- | lib/elixir/lib/stream/reducers.ex | 2 | ||||
-rw-r--r-- | lib/elixir/test/elixir/stream_test.exs | 10 |
4 files changed, 45 insertions, 8 deletions
diff --git a/lib/elixir/lib/enum.ex b/lib/elixir/lib/enum.ex index 0e702d668..8727d1b5e 100644 --- a/lib/elixir/lib/enum.ex +++ b/lib/elixir/lib/enum.ex @@ -2381,6 +2381,7 @@ defmodule Enum do The function `fun` maps every element to a term which is used to determine if two elements are duplicates. + ## Example iex> Enum.uniq_by([{1, :x}, {2, :y}, {1, :z}], fn {x, _} -> x end) @@ -2397,7 +2398,7 @@ defmodule Enum do end def uniq_by(enumerable, fun) when is_function(fun, 1) do - {list, _} = reduce(enumerable, {[], %{}}, R.uniq(fun)) + {list, _} = reduce(enumerable, {[], %{}}, R.uniq_by(fun)) :lists.reverse(list) end diff --git a/lib/elixir/lib/stream.ex b/lib/elixir/lib/stream.ex index 48a01ce66..a0f684a6d 100644 --- a/lib/elixir/lib/stream.ex +++ b/lib/elixir/lib/stream.ex @@ -837,14 +837,42 @@ defmodule Stream do iex> Stream.uniq([1, 2, 3, 3, 2, 1]) |> Enum.to_list [1, 2, 3] - iex> Stream.uniq([{1, :x}, {2, :y}, {2, :z}, {1, :x}], fn {x, _} -> x end) |> Enum.to_list + """ + @spec uniq(Enumerable.t) :: Enumerable.t + def uniq(enum) do + uniq_by(enum, fn x -> x end) + end + + @doc false + # TODO: Deprecate by 1.4 + def uniq(enum, fun) do + uniq_by(enum, fun) + end + + @doc """ + Creates a stream that only emits elements if they are unique, by removing the + elements for which function `fun` returned duplicate items. + + The function `fun` maps every element to a term which is used to + determine if two elements are duplicates. + + Keep in mind that, in order to know if an element is unique + or not, this function needs to store all unique values emitted + by the stream. Therefore, if the stream is infinite, the number + of items stored will grow infinitely, never being garbage collected. + + ## Example + + iex> Stream.uniq_by([{1, :x}, {2, :y}, {1, :z}], fn {x, _} -> x end) |> Enum.to_list [{1, :x}, {2, :y}] + iex> Stream.uniq_by([a: {:tea, 2}, b: {:tea, 2}, c: {:coffee, 1}], fn {_, y} -> y end) |> Enum.to_list + [a: {:tea, 2}, c: {:coffee, 1}] + """ - @spec uniq(Enumerable.t) :: Enumerable.t - @spec uniq(Enumerable.t, (element -> term)) :: Enumerable.t - def uniq(enum, fun \\ fn x -> x end) do - lazy enum, %{}, fn f1 -> R.uniq(fun, f1) end + @spec uniq_by(Enumerable.t, (element -> term)) :: Enumerable.t + def uniq_by(enum, fun) do + lazy enum, %{}, fn f1 -> R.uniq_by(fun, f1) end end @doc """ diff --git a/lib/elixir/lib/stream/reducers.ex b/lib/elixir/lib/stream/reducers.ex index c017c5995..827135f00 100644 --- a/lib/elixir/lib/stream/reducers.ex +++ b/lib/elixir/lib/stream/reducers.ex @@ -195,7 +195,7 @@ defmodule Stream.Reducers do end end - defmacro uniq(callback, f \\ nil) do + defmacro uniq_by(callback, f \\ nil) do quote do fn(entry, acc(h, prev, t) = acc) -> value = unquote(callback).(entry) diff --git a/lib/elixir/test/elixir/stream_test.exs b/lib/elixir/test/elixir/stream_test.exs index bf354fb84..7d18be9ef 100644 --- a/lib/elixir/test/elixir/stream_test.exs +++ b/lib/elixir/test/elixir/stream_test.exs @@ -865,7 +865,7 @@ defmodule StreamTest do assert Enum.zip(list, list) == Enum.zip(stream, stream) end - test "uniq/1" do + test "uniq/1 & uniq/2" do assert Stream.uniq([1, 2, 3, 2, 1]) |> Enum.to_list == [1, 2, 3] @@ -873,6 +873,14 @@ defmodule StreamTest do [{1, :x}, {2, :y}] end + test "uniq_by/2" do + assert Stream.uniq_by([{1, :x}, {2, :y}, {1, :z}], fn {x, _} -> x end) |> Enum.to_list == + [{1, :x}, {2, :y}] + + assert Stream.uniq_by([a: {:tea, 2}, b: {:tea, 2}, c: {:coffee, 1}], fn {_, y} -> y end) |> Enum.to_list == + [a: {:tea, 2}, c: {:coffee, 1}] + end + test "zip/2" do concat = Stream.concat(1..3, 4..6) cycle = Stream.cycle([:a, :b, :c]) |