How to Count Specific Items in a Collection with Elixir

So, I was working on this exercise over at, when I stumbled up an interesting function.

To make a long story short, I needed a count of a specific character (codepoint) in a character list i.e. 'hello' contains two ls. However, this solution could apply to any collection which implements the Enumerable protocol in Elixir.

I have been reading Programming in Elixir. The author, Dave Thomas, emphasizes the use of recursion and pattern matching throughout Elixir. So, of course, I had implemented the solution using recursion and pattern matching. You can see that solution here.

You Can Count (Ha!) on Elixir

Of course, I missed the obvious. Elixir already had a very convenient function for doing exactly this: Enum.count/2.

I had anticipated that Elixir would have a function to do a straight count of all the items in a collection (which it does: `Enum.count/1′). However, I had not considered one for looking for a specific kind of item.

Well, Enum.count/2 provides a convenient API for this exact problem. You simply pass the enumerable (in my case, the character list) and a function which takes one argument (the current item) and will return true for whatever items you want to count.

Here’s a convenient graphic to demonstrate:

Elixir Enum Count

Elixir Enum.count/2 Examples

Of course, the expression used to evaluate the current item does not need to be a simple equality operation. Here are some examples using a variety of different operators:

Count all the binaries (strings) which equal “price”:

Enum.count(["Total", "retail", "price", "$14.95"], &(&1 == "price"))

Pipe syntax:

["Total", "retail", "price", "$14.95"]
  |> ... # some other functions
  |> Enum.count(&(&1 == "price"))

Count all the binaries which are members of a list:

roles = ["User", "Customer", "Partner", "Admin"]
Enum.count(roles, &Enum.member?(["Admin", "Editor", "Developer"], &1))

Count all the binaries (strings) which match a regular expression:

Enum.count(["Total", "price", "$14.95"], &(&1 =~ ~r/\$\d+\.\d+/))

Count all the binaries (strings) in a list:

Enum.count([1, "list", 3], &is_binary(&1))

Count all the binaries (strings) in a multi-type list:

Enum.count([1, "list", 3], &is_binary(&1))

Count all the integers in a multi-type list:

Enum.count([1, "list", 3], &is_integer(&1))

Count all the integers greater than 3:

Enum.count([1,2,4,8,16,32], &(&1 > 3))

Read the documentation on Enum.count/2

This post is part of my series of Elixir Tutorials

  • hugolnx

    To count char in binaries you can also use bitstring comprehension:
    (for << <> >, c == ?l, do: 1) |> length()

    It is more efficient than converting it to a charlist, though is “uglier” hehe

    ## CountBinaryBench
    benchmark name average time
    bitstring comprehension 4.05 µs/op
    converting to charlist 12.46 µs/op

    benchmark using:

    • Good point. Yeah, maybe not the ‘prettiest’ solution, but more efficient. Thanks for sharing!