From 075725248a932cf8cfcfec02f8dda2c9e833aed3 Mon Sep 17 00:00:00 2001 From: qwyng Date: Mon, 30 Sep 2019 22:58:43 +0900 Subject: [PATCH] add Enum.tally --- lib/elixir/lib/enum.ex | 21 +++++++++++++++++++++ lib/elixir/test/elixir/enum_test.exs | 10 ++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/elixir/lib/enum.ex b/lib/elixir/lib/enum.ex index 78efcef5cc0..1db528fd81b 100644 --- a/lib/elixir/lib/enum.ex +++ b/lib/elixir/lib/enum.ex @@ -1147,6 +1147,27 @@ defmodule Enum do end) end + @doc """ + creates a new map with keys as unique elements from enumerable, + and set values as the count of every element + + The order of elements within each list is preserved from the `enumerable`. + + ## Examples + + iex> Enum.tally(~w{ant buffalo ant ant buffalo dingo}) + %{"ant" => 3, "buffalo" => 2, "dingo" => 1} + + iex> Enum.tally(~w{aa aA bb cc}, fn x -> String.downcase(x) end) + %{"aa" => 2, "bb" => 1, "cc" => 1} + """ + @spec tally(t, (element -> any)) :: map + def tally(enumerable, func \\ fn x -> x end) do + group_by(enumerable, func) + |> map(fn {key, val} -> {key, count(val)} end) + |> Map.new() + end + @doc """ Intersperses `element` between each element of the enumeration. diff --git a/lib/elixir/test/elixir/enum_test.exs b/lib/elixir/test/elixir/enum_test.exs index 2edde39e004..1ea51504822 100644 --- a/lib/elixir/test/elixir/enum_test.exs +++ b/lib/elixir/test/elixir/enum_test.exs @@ -279,6 +279,16 @@ defmodule EnumTest do assert Enum.group_by([1, 2, 3], &rem(&1, 2)) == %{0 => [2], 1 => [1, 3]} end + test "tally/2" do + assert Enum.tally(~w{a a a b c c}) == %{"a" => 3, "b" => 1, "c" => 2} + + assert Enum.tally(~w{aa aA bb cc}, fn x -> String.downcase(x) end) == %{ + "aa" => 2, + "bb" => 1, + "cc" => 1 + } + end + test "intersperse/2" do assert Enum.intersperse([], true) == [] assert Enum.intersperse([1], true) == [1]