Sorting By Functions in Crystal
Sometimes we’ll want to sort a collection by something other than its natural order. For example, suppose we wanted to sort strings by their length instead of alphabetically. Here’s an example of custom sorts in Crystal.
# We don't need to import any modules for this example in Crystal
# Define our main function
def main
fruits = ["peach", "banana", "kiwi"]
# We implement a comparison function for string lengths.
len_cmp = ->(a : String, b : String) { a.size <=> b.size }
# Now we can call `sort_by!` with this custom comparison function
# to sort `fruits` by name length.
fruits.sort_by! { |f| f.size }
puts fruits
# We can use the same technique to sort an array of
# values that aren't built-in types.
class Person
property name : String
property age : Int32
def initialize(@name, @age)
end
def to_s
"{#{name}, #{age}}"
end
end
people = [
Person.new("Jax", 37),
Person.new("TJ", 25),
Person.new("Alex", 72)
]
# Sort `people` by age using `sort_by!`.
people.sort_by! { |person| person.age }
puts people
end
main
In this Crystal version:
We don’t need to import any modules as Crystal’s standard library is available by default.
Instead of
slices.SortFunc
, we use Crystal’s built-insort_by!
method which sorts the array in-place.The comparison function is simplified to use Crystal’s spaceship operator
<=>
.For sorting custom types, we define a
Person
class instead of a struct. Crystal uses classes for this kind of structure.We use Crystal’s property syntax to automatically create getter and setter methods for
name
andage
.We implement a
to_s
method forPerson
to make the output more readable.The sorting of
people
is done using the samesort_by!
method, specifying theage
property to sort by.
When you run this program, you should see output similar to:
["kiwi", "peach", "banana"]
[{TJ, 25}, {Jax, 37}, {Alex, 72}]
This example demonstrates how to perform custom sorting in Crystal, both for built-in types and custom classes.