I want to count the number of word-occurrences in a string. The implementation is questionable, but lets use it to demonstrate my problem:
def count(sentence) do
words = String.split(sentence)
occurrences = Enum.map(words, fn w -> {w, Enum.count(words, &(&1 == w))} end)
Map.new(occurrences)
end
I would like to achieve the same result as above, but using pipes instead of intermediate result variables:
def count(sentence) do
sentence
|> String.split
|> Enum.map(fn w -> {w, Enum.count(???)} end)
|> Map.new
end
Is it possible to reference the piped in value in the Enum.count function? Or do i have to use an intermediate variable?
You can put an anonymous function in the pipeline:
def count(sentence) do
sentence
|> String.split
|> (fn words -> Enum.map(words, fn w -> {w, Enum.count(words, &(&1 == w))} end) end).()
|> Map.new
end
iex(1)> count("foo bar baz foo")
%{"bar" => 1, "baz" => 1, "foo" => 2}
Though the @Dogbert’s answer is perfectly correct, I would add a sidenote: it seems that as soon as you need the pipe-out value twice, you’re likely doing it wrong. The above example might be rewritten as:
def count(sentence) do
sentence
|> String.split
|> Enum.reduce(%{}, fn e, acc ->
Map.put(acc, e, (Map.get(acc, e) || 0) + 1)
end)
end
or in many other ways, that reduce an amount of loops involved (and, hence, the big-O of the whole function.)
Modern era update: starting with v1.8
, Kernel.SpecialForms.for/1
comprehension has a reduce:
keyword parameter, that makes the above even easier to grasp:
def count(sentence) do
for word <- String.split(sentence), reduce: %{} do
%{^word => count} = acc -> %{acc | word => count + 1}
acc -> Map.put(acc, word, 1)
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With