Next, what I want to do is traverse over each string in this list and basically keep track of each of their letters. For example, I traverse over the word “eggs” and with each traversal (would be 4 in total), I mark an index of some array that “e” just got traversed, “g” just got traversed, and so on.
I’d build a MapSet containing traversed characters and compute the size at the end (if you do not care about duplicate characters) or a Map using Map.update if you want to count characters. It really depends on what your end goal is.
That is a good idea. One additional thing I would like to ask over here is that how would you actually traverse the characters? Like when I try using Stream.flat_map or Stream.reduce, it keeps giving me the following error:
protocol Enumerable not implemented for “eggs” of type BitString
I tend to separate the iterator (or traverser) from the processor. I also use graphemes over code points since Elixir strings are UTF8 and may be 1..3 bytes and a grapheme cluster (like emoji) even longer. For example:
defmodule Iter do
@doc """
Traverse a list of strings and call the supplied function for each
grapheme in each string.
"""
@spec traverse(list(String.t), function()) :: any()
def traverse(strings, fun, acc \\ Map.new()) when is_list(strings) and is_function(fun) do
Enum.reduce(strings, acc, fn string, acc ->
string
|> String.graphemes()
|> Enum.reduce(acc, fun)
end)
end
# An example function called for each grapheme in the list of strings.
# This example just updates the accumulator with the grapheme count.
def fun(char, acc) do
Map.update(acc, char, 1, fn count -> count + 1 end)
end
end