Skip to content

Instantly share code, notes, and snippets.

@mcelaney
Last active March 20, 2017 19:46
Show Gist options
  • Save mcelaney/9c5a480749117c062692d0c3bad55e93 to your computer and use it in GitHub Desktop.
Save mcelaney/9c5a480749117c062692d0c3bad55e93 to your computer and use it in GitHub Desktop.
March 20, 2017 PhillyDevSlack #DailyProgrammer
defmodule Thing do
@moduledoc """
Sort a string by cardinality of repeating characters, then alphabetically within each partition created by cardinality sorting.
An example: "abcdddeeeffff" would be sorted "ffffdddeeeabc"
In the above, 'f' appears the most(4), so it comes first, followed by 'd's and 'e's (3), in alaphabetical order, since they have equal cardinality. Then follow 'a', 'b', and 'c' in alphabetical order since they all have the same cardinality(1).
Another example: "cardinality" would be sorted "aaiicdlnrty"
"""
@doc """
## Example
iex> Thing.perform("cardinality")
"aaiicdlnrty"
iex> Thing.perform("abcdddeeeffff")
"ffffdddeeeabc"
"""
def perform(word) when is_binary(word) do
word |> String.graphemes |> perform
end
def perform(characters) do
characters
|> Enum.group_by(fn(letter) -> letter end)
|> Enum.reduce(%{}, fn({letter, incidents}, acc) ->
map_by_count(letter, Enum.count(incidents), acc)
end)
|> Enum.reduce("", fn({_, letter_map}, acc) ->
cobble_string(letter_map) <> acc
end)
end
@doc """
This will take a letter and a count and then will add them to a given
accumulator value.
## Example
iex> Thing.map_by_count("b", 3, %{3 => %{"i" => "iii"}})
%{3 => %{"b" => "bbb", "i" => "iii"}}
iex> Thing.map_by_count("b", 3, %{2 => %{"f" => "fff"}})
%{2 => %{"f" => "fff"}, 3 => %{"b" => "bbb"}}
"""
def map_by_count(letter, count, acc) do
Map.put(acc, count, _map_by_count(letter, count, acc))
end
def _map_by_count(letter, count, acc) do
if Map.has_key?(acc, count) do
Map.merge(acc[count], build_letter_map(letter, count))
else
build_letter_map(letter, count)
end
end
@doc """
This will take a letter and a count and return a map with a single key (the
letter) with aprintable value.
## Example
iex> Thing.build_letter_map("a", 3)
%{"a" => "aaa"}
"""
def build_letter_map(letter, count), do: %{letter => String.duplicate(letter, count)}
@doc """
Accepts an enumerable which contains keys for each letter and strings as the
values. Takes the values for each and concats them.
Since enum orders the values this will always print in alphabetical order
## Example
iex> Thing.cobble_string(%{"l" => "ll", "c" => "cc", "n" => "nn"})
"ccllnn"
"""
def cobble_string(letter_map) do
letter_map
|> Map.values
|> Enum.join("")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment