Count String

Hello Communiity,

I would like know which is the best form for count one string with the following format

input = “abcaaabbb”

output =“abca3b3”

Regards

Here’s my try:

input
|> String.graphemes()
|> Enum.chunk_by(& &1)
|> Enum.map_join(fn
  [char] ->  char
  [char | _] = chars ->  [char, length(chars) |> to_string()]
end)
1 Like

A recursive try…

defmodule Demo do
  def compress(str) when is_binary(str) do
    do_compress(str, {<<>>, nil, 0})
  end

  defp do_compress(<<>>, {acc, _previous, 0}), do: acc
  defp do_compress(<<>>, {acc, previous, count}),
    do: acc <> <<previous::utf8>> <> to_string(count + 1)
  defp do_compress(<<c::utf8, rest::binary>>, {acc, previous, count})
    when c == previous,
    do: do_compress(rest, {acc, previous, count + 1})
  defp do_compress(<<c::utf8, rest::binary>>, {acc, _previous, 0}),
    do: do_compress(rest, {acc <> <<c::utf8>>, c, 0})
  defp do_compress(<<c::utf8, rest::binary>>, {acc, _previous, count}),
    do: do_compress(rest, {acc <> to_string(count + 1), c, 0})
end

then…

iex(1)> Demo.compress "abcaaabbb"
"abca3b3"
2 Likes

Great Solutions, Thanks qhwa, mudasobwa, kokolegorille

wouldn’t let you get away without a solution featuring TCR and improper lists!

defmodule Demo do
  def compress(str) when is_binary(str) do
    str
    |> do_compress({[], 1})
    |> IO.iodata_to_binary()
  end

  #terminal condition
  def do_compress("", {acc, _}), do: acc
  def do_compress(str = <<char::utf8, char::utf8, _::binary>>, {acc, count}) do
    # drop the first character and increment the count
    <<_::utf8>> <> rest = str
    do_compress(rest, {acc, count + 1})
  end
  def do_compress(<<char::utf8>> <> rest, {acc, 1}) do
    # no match, singleton, don't tag; reset count.
    do_compress(rest, {[acc | <<char::utf8>>], 1})
  end
  def do_compress(<<char::utf8>> <> rest, {acc, n}) do
    # no match, multiples, add the tag, reset count.
    do_compress(rest, {[acc, <<char::utf8>> | to_string(n)], 1})
  end
end