47 lines
1.7 KiB
Elixir
47 lines
1.7 KiB
Elixir
defmodule RunLengthEncoder do
|
|
@digits ~w(0 1 2 3 4 5 6 7 8 9)
|
|
|
|
defguardp is_digit(char) when char in @digits
|
|
|
|
defp encode_reducer(char, []), do: [{char, 1}]
|
|
defp encode_reducer(char, [{char, count} | rest]), do: [{char, count + 1} | rest]
|
|
defp encode_reducer(char, rest), do: [{char, 1} | rest]
|
|
|
|
defp encode_mapper({char, 1}), do: char
|
|
defp encode_mapper({char, count}), do: "#{count}#{char}"
|
|
|
|
defp decode_reducer(digit, []) when is_digit(digit), do: [{nil, digit}]
|
|
defp decode_reducer(digit, [{nil, count} | rest]) when is_digit(digit), do: [{nil, count <> digit} | rest]
|
|
defp decode_reducer(char, [{nil, count} | rest]) when not is_digit(char), do: [{char, String.to_integer(count)} | rest]
|
|
defp decode_reducer(digit, rest) when is_digit(digit), do: [{nil, digit} | rest]
|
|
defp decode_reducer(char, rest), do: [{char, 1} | rest]
|
|
|
|
defp decode_mapper({char, 1}), do: char
|
|
defp decode_mapper({char, count}), do: String.duplicate(char, count)
|
|
|
|
@doc """
|
|
Generates a string where consecutive elements are represented as a data value and count.
|
|
"AABBBCCCC" => "2A3B4C"
|
|
For this example, assume all input are strings, that are all uppercase letters.
|
|
It should also be able to reconstruct the data into its original form.
|
|
"2A3B4C" => "AABBBCCCC"
|
|
"""
|
|
@spec encode(String.t()) :: String.t()
|
|
def encode(string) do
|
|
string
|
|
|> String.graphemes()
|
|
|> Enum.reduce([], &encode_reducer/2)
|
|
|> Enum.reverse()
|
|
|> Enum.map_join(&encode_mapper/1)
|
|
end
|
|
|
|
@spec decode(String.t()) :: String.t()
|
|
def decode(string) do
|
|
string
|
|
|> String.graphemes()
|
|
|> Enum.reduce([], &decode_reducer/2)
|
|
|> Enum.reverse()
|
|
|> Enum.map_join(&decode_mapper/1)
|
|
end
|
|
end
|