Count words in string and tally up the repetitive words I'm an elixir beginner.  I'm doing the word count exercise of exercism website.  The word count exercise returns a map with the word as the key and the number of instances as value.  The exercise excludes special characters, and ignores underscores. My code works, but I'm sure there is a way to make it cleaner.  I've attached the test file so that you can see the criteria that it needs to pass.

word_count.exs

defmodule Words do
  @doc """
  Count the number of words in the sentence.

  Words are compared case-insensitively.
  """
  @spec count(String.t) :: map
  def count(sentence) do
    String.downcase(sentence)                                           |&gt;
      String.split(~r/[\s_]/)                                           |&gt;
      Enum.filter(fn(word) -&gt; String.match?(word, ~r/[a-zA-z\d]/) end)  |&gt;
      Enum.map(fn(word) -&gt; String.replace(word, ~r/[:!&amp;@$%^,]/, "") end)|&gt;
      Enum.group_by(fn(word) -&gt; word end)                               |&gt;
      Enum.reduce(%{}, fn({k, v}, acc) -&gt; Map.put(acc, k, Enum.count(v)) end)
  end
end


word_count_test.exs

if !System.get_env("EXERCISM_TEST_EXAMPLES") do
  Code.load_file("word_count.exs")
end

ExUnit.start
ExUnit.configure exclude: :pending, trace: true

defmodule WordsTest do
  use ExUnit.Case

  test "count one word" do
    assert Words.count("word") == %{ "word" =&gt; 1 }
  end

  test "count one of each" do
    expected = %{ "one" =&gt; 1 ,  "of" =&gt; 1 ,  "each" =&gt; 1 }
    assert Words.count("one of each") == expected
  end

  test "count multiple occurrences" do
    expected = %{ "one" =&gt; 1 ,  "fish" =&gt; 4 ,  "two" =&gt; 1 ,  "red" =&gt; 1 ,  "blue" =&gt; 1 }
    assert Words.count("one fish two fish red fish blue fish") == expected
  end

  test "ignore punctuation" do
    expected = %{"car" =&gt; 1, "carpet" =&gt; 1, "as" =&gt; 1, "java" =&gt; 1, "javascript" =&gt; 1}
    assert Words.count("car : carpet as java : javascript!!&amp;@$%^&amp;") == expected
  end

  test "include numbers" do
    expected = %{"testing" =&gt; 2, "1" =&gt; 1, "2" =&gt; 1}
    assert Words.count("testing, 1, 2 testing") == expected
  end

  test "hyphens" do
    expected = %{"co-operative" =&gt; 1}
    assert Words.count("co-operative") == expected
  end

  test "ignore underscores" do
    expected = %{"two" =&gt; 1, "words" =&gt; 1}
    assert Words.count("two_words") == expected
  end

  test "normalize case" do
    expected = %{"go" =&gt; 3}
    assert Words.count("go Go GO") == expected
  end

  test "German" do
    expected = %{"götterfunken" =&gt; 1, "schöner" =&gt; 1, "freude" =&gt; 1}
    assert Words.count("Freude schöner Götterfunken") == expected
  end
end
Just finished that exercise too.
I think you can extract some of that logic to anonymous functions.
It isolates a pieces of behaviour that you can work on.

defmodule Words do
  @doc """
  Count the number of words in the sentence.

  Words are compared case-insensitively.
  """
  @spec count(String.t) :: map
  def count(sentence) do
    filter_word = fn(word) -&gt;
      String.match?(word, ~r/[a-zA-z\d]/)
    end

    remove_special_characters = fn(word) -&gt;
      String.replace(word, ~r/[:!&amp;@$%^,]/, "")
    end

    count_words = fn({k, v}, acc) -&gt;
      Map.put(acc, k, Enum.count(v))
    end

    sentence
    |&gt; String.downcase
    |&gt; String.split(~r/[\s_]/)
    |&gt; Enum.filter(filter_word)
    |&gt; Enum.map(remove_special_characters)
    |&gt; Enum.group_by(fn(word) -&gt; word end)
    |&gt; Enum.reduce(%{}, count_words)
  end

end


And actually, I've created a function that returns a list of words to count: http://exercism.io/submissions/e26667aff3734da79ac0b6c6fedfd3da

Hope that helps!