Andres
Count the number of non-numeric characters in a string and then sum their values
Hello.
Trying to solve this problem I wrote the following algorithm:
string = "3340c9571y40m47ku49t9315mrvzqo667k36e"
# %{
# "c" => 1,
# "e" => 1,
# "k" => 2,
# "m" => 2,
# "o" => 1,
# "q" => 1,
# "r" => 1,
# "t" => 1,
# "u" => 1,
# "v" => 1,
# "y" => 1,
# "z" => 1
# }
# [1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1]
# Expected result => 14
def is_numeric?(char) do
Regex.match?(~r/^\d+$/, char)
end
def total_non_numeric_chars(string) do
String.codepoints(string)
|> Enum.reduce(%{}, fn char, acc ->
cond do
!is_numeric?(char) ->
if Map.has_key?(acc, char),
do: Map.update!(acc, char, &(&1 + 1)),
else: Map.put(acc, char, 1)
true ->
acc
end
end)
|> Map.values()
|> Enum.sum()
end
I would like to know if is possible to avoid the nested cond and if with some patter matching or other technique.
Any suggestions to improve the algorithm is welcome.
Thanks.
Marked As Solved
michalmuskala
I just thought of using the new reduce comprehensions. With that it can be a one-liner:
for << <<char>> <- string >>, char not in ?0..?9, reduce: 0, do: (acc -> acc + 1)
Also Liked
michalmuskala
Since you’re summing them up at the end, I guess you don’t really need to keep the frequency map - you can just keep the sum (unless you also output the map somewhere).
With that in mind, this is how I’d write it:
def total_non_numeric_chars(string), do: loop(string, 0)
defp loop(<<char, rest::binary>>, count) when char in ?0..?9, do: loop(rest, count)
defp loop(<<_, rest::binary>>, count), do: loop(rest, count + 1)
defp loop(<<>>, count), do: count
NobbZ
Just be aware of the fact that is_numeric? is an unidiomatic name for a function, either we use the prefix is_ when we have guardsave predicates or we use the suffix ? when the predicate is not guardsafe.
mudasobwa
It could be a one-liner even without new fancy reduce comprehension option ![]()
length(for << char <- string >>, char not in ?0..?9, do: char)
# or
byte_size(for << char <- string >>, char not in ?0..?9, into: "", do: <<char>>)
LostKobrakai
if !is_numeric?(char) do
Map.update(acc, char, 1, &(&1 + 1))
else
acc
end







