lapinkoira
lapinkoira

Reputation: 8998

Count how many keys are in a list

Is there an idiomatic way to calculate how many times appear the key test in this list?

[%{"test" => 1}, %{"test" => 3}, %{"test2" => 1}]

I would define a variable and use Enum.each or for -> but I know there must be a way to do it more functional.

Upvotes: 1

Views: 1202

Answers (2)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

Just out of curiosity, exotic answer using Kernel.SpecialForms.for/1 comprehension:

String.length(
  for %{"test" => _} <- [%{"test" => 1}, %{"test" => 3}, %{"test2" => 1}],
    do: <<"+">>, into: ""
)

It’s better extended to the case when we have a list of lists:

String.length(
  for list <- lists, %{"test" => _} <- list, do: <<"+">>, into: ""
)

If Collectable protocol was implemented for Integer, it could have been written even in more concise way:

for %{"test" => _} <- [%{"test" => 1}, %{"test" => 3}, %{"test2" => 1}],
  do: 1, into: 0

But unfortunately, it does not :)

Upvotes: 2

Dogbert
Dogbert

Reputation: 222368

You can use Enum.count/2 and Map.has_key?/2:

iex(1)> list = [%{"test" => 1}, %{"test" => 3}, %{"test2" => 1}]
[%{"test" => 1}, %{"test" => 3}, %{"test2" => 1}]
iex(2)> Enum.count(list, &Map.has_key?(&1, "test"))
2

As requested in comment below, here's how to count in a list of lists:

iex(3)> lists = [list, list, list]
[[%{"test" => 1}, %{"test" => 3}, %{"test2" => 1}],
 [%{"test" => 1}, %{"test" => 3}, %{"test2" => 1}],
 [%{"test" => 1}, %{"test" => 3}, %{"test2" => 1}]]
iex(4)> lists |> Enum.reduce(0, fn list, acc -> acc + Enum.count(list, &Map.has_key?(&1, "test")) end)
6

Upvotes: 3

Related Questions