neuone
Sorting a list alphabetic then numeric
Scenario
I have a list I’m getting back where I have a mixture of letters and numbers as strings. I need the list to be sorted so it’s alphabetic first THEN numeric.
# Sample data
[
{"1",[]},
{"A",[]},
{"B",[]},
{"C",[]},
{"D",[]},
{"E",[]},
{"F",[]},
{"3",[]},
{"4",[]},
{"5",[]},
{"6",[]}
]
# But I want this as the final result
[
{"A", []},
{"B", []},
{"C", []},
{"D", []},
{"E", []},
{"F", []},
{"1", []},
{"3", []},
{"4", []}
]
My solution works
This is what I came up with and it seems to work
defmodule Foo do
@list [
{"1",[]},
{"A",[]},
{"B",[]},
{"C",[]},
{"D",[]},
{"E",[]},
{"F",[]},
{"3",[]},
{"4",[]},
{"5",[]},
{"6",[]}
]
def list do
@list
end
def sort_alpha_then_numeric(list) do
numbers_alpabetic_list =
Enum.split_with(list, fn item ->
{key, _value} = item
case Integer.parse(key) do
{_, ""} -> true
:error -> false
end
end)
{number_list, alpha_list} = numbers_alpabetic_list
# We now switch it so that the order is alpabetic then numeric
List.flatten(alpha_list, number_list)
end
end
So if I try this out
Foo.sort_alpha_then_numeric Foo.list
# returns
[
{"A", []},
{"B", []},
{"C", []},
{"D", []},
{"E", []},
{"F", []},
{"1", []},
{"3", []},
{"4", []}
]
Question
It works, but would like to know if my approach can be improved and learn something about sorting. Thanks.
Most Liked
hauleth
Using function proposed by @LostKobrakai:
def sort(list), do: Enum.sort_by(list, &comparator/2)
defp comparator(<<a, _::binary>> = ax, <<b, _::binary>> = bx) when a in ?0..?9 and b in ?0..9, do: ax <= bx
defp comparator(<<a, _::binary>>, _) when a in ?0..?9, do: true
defp comparator(ax, bx), do: ax <= bx
However it is not clear how "0a" should compare with "01". I assumed that only first character decides. Otherwise you need to expand comparator/2 function a little.
EDIT: Fixed snippet, the in operator was missing.
hauleth
No, this is pattern matching on binaries. We are getting out first byte and then ignoring the rest _ has type binary. More info Kernel.SpecialForms.<<>>








