kimc0de
How to compare integer in a list and return a list of integer and its frequencies
Hi all, I’m trying to do some Leetcode exercises in elixir.
I have a function that takes an integer and it needs to return a list of lists that includes the digit frequency and the digit itself.
Something list this for example number = 11223411 => return [ [2,1], [2,2], [1,3] [1,4], [2,1] ]
The first number is the frequency and the second one is the digit itself. I’m stuck on counting the digit.
So here’s where I am
list_of_integer = Integer.digits(number)
list_length = len(list_of_integer)
for n <- 0..(list_length-2) do
if (Enum.at(list_of_integer, n) == (Enum.at(list_of_integer, n + 1))) do
# here am not really sure what to do next.. is it the right approach tho? :(
end
end
This Leetcode is number 38 ‘count and say’. If anyone has done it, I would appreciate it if you could share your approach to solving this.
Marked As Solved
al2o3cr
A general note: 99.9% of the time, if you find yourself writing Enum.at inside of a loop - especially with an index value that can go all the way to the end - you should consider a different approach. The motivation is that every call to Enum.at takes time proportional to the index so accessing elements at the end gets increasingly expensive.
For this specific problem, it’s worth calling out how this isn’t solved by Integer.digits + Enum.frequencies: the digits are only counted when they are together.
Skimming through the list of functions in Enum (you should do this, A LOT) we find a promising function: chunk_by:
https://hexdocs.pm/elixir/Enum.html#chunk_by/2
An example of using this looks like:
number
|> Integer.digits()
|> Enum.chunk_by(& &1)
which would result in [[1, 1], [2, 2], [3], [4], [1, 1]] where each element of the list is a list of the same number over and over.
Then you can transform that result into the counts you’re expecting:
number
|> Integer.digits()
|> Enum.chunk_by(& &1)
|> Enum.map(fn many_digits -> [length(many_digits), hd(many_digits)] end)
Also Liked
LostKobrakai
With elixir you don’t (and usually can’t) solve issues by using loops like you’d do in non-functional languages. You’d want to look into reducing over your data to get to the expected result. for might look like a loop, but it’s not.
kokolegorille
You should try not to think how You would solve this in your previous language. It will only slow You down.
A good start, as mentionned by @al2o3cr is to learn the Enum module.
A solution with Enum.reduce might look like this. What You need to understand, value don’t change, but can be transformed.
{list, previous, count} = Enum.reduce(list_of_integer, {[], nil, 0}, fn integer, {list, previous, count} ->
if integer == previous do
... return an acc with incremented count
else
... return an acc with count = 1, previous = integer, update list with new element
end
end)
mpope
Could use Enum.reduce/3!
reducer = fn (digit, acc) ->
case acc[digit] do
nil -> Map.put(acc, digit, 1)
current_count -> Map.put(acc, digit, current_count + 1)
end
end
11223411
|> Integer.to_string
|> String.graphemes
|> Enum.reduce(%{}, reducer)
|> Map.to_list
Result: [{"1", 4}, {"2", 2}, {"3", 1}, {"4", 1}]







