summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Entin <whoknew@gmail.com>2016-07-03 16:23:11 -0400
committerJosé Valim <jose.valim@gmail.com>2016-07-03 22:23:11 +0200
commit652c40875e0ed4528206a28a33047717b27324bd (patch)
tree27a1bac9df1c60f8e34b208fd1608bb8139eb630
parentdb8836c08f11cd738b50b0b1d9d9b252fb52827b (diff)
downloadelixir-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.ex3
-rw-r--r--lib/elixir/lib/stream.ex38
-rw-r--r--lib/elixir/lib/stream/reducers.ex2
-rw-r--r--lib/elixir/test/elixir/stream_test.exs10
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])