Skip to content

Instantly share code, notes, and snippets.

@walquis
Last active December 4, 2021 20:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save walquis/4d3fb23826d3427d0ea5 to your computer and use it in GitHub Desktop.
Save walquis/4d3fb23826d3427d0ea5 to your computer and use it in GitHub Desktop.
Ruby examples of sorting, including overriding spaceship operator

Run with this:

$ bundle exec rspec test_spec.rb

source 'http://rubygems.org'
gem 'rspec'
class MyObject
attr_reader :name, :size
def initialize name, size
@size = size
@name = name
end
def <=> other
size <=> other.size
end
end
require './my_object'
describe "array-of-int sorting" do
before :each do
@ary = 5.downto(1)
end
it "sorts an array of numbers" do
expect(@ary.sort).to eql [1,2,3,4,5]
end
it "sorts an array of numbers with <=>" do
expect(@ary.sort { |a,b| a <=> b} ).to eql [1,2,3,4,5]
end
end
describe "hash sorting" do
it "sorts a hash of ints" do
h = { a: 5, b: 4, c: 3 }
expect(h.sort_by {|k,v| v}.map{ |k,v| v }).to eql [3,4,5]
expect(h.sort_by {|k,v| v}.map{ |k,v| k }).to eql [:c, :b, :a]
sorted = h.sort_by {|k,v| v}
expect(sorted.class).to eql Array # Surprise! Not a hash any more
expect(sorted.first.class).to eql Array # An array of arrays
sorted = Hash[*sorted.flatten] # Turn it back into a hash
expect(sorted.class).to eql Hash
expect(sorted.keys).to eql [:c, :b, :a]
end
context "hashes of hashes" do
before :each do
@h = {
n: {p1: 'cstring'},
p: {p1: 'bstring'},
k: {p1: 'astring'}
}
end
it "sorts a hash of objects with default sort, which is by-key" do
expect(@h.keys).to eql [:n, :p, :k] # Ruby's Hash order is preserved
expect(Hash[*@h.sort.flatten].keys).to eql [:k, :n, :p]
end
it "sorts a hash of objects with sort block and <=> b (tie-fighter) comparison...also by-key" do
expect(@h.keys).to eql [:n, :p, :k] # Ruby's Hash order is preserved
sorted = @h.sort { |a,b| a <=> b }
expect(Hash[*sorted.flatten].keys).to eql [:k, :n, :p]
end
it "sorts a hash of objects using with sort block and <=> compare of a and b" do
expect(@h.keys).to eql [:n, :p, :k] # Ruby's Hash order is preserved
sorted = @h.sort { |a,b|
a[1][:p1] <=> b[1][:p1]
}
expect(Hash[*sorted.flatten].keys).to eql [:k, :p, :n]
end
it "sorts a hash of objects with sort_by block; the args are |k,v|, not |a,b|" do
expect(@h.keys).to eql [:n, :p, :k] # Ruby's Hash order is preserved
sorted = @h.sort_by { |k,v|
v[:p1]
}
expect(Hash[*sorted.flatten].keys).to eql [:k, :p, :n]
end
end
context "sorting arbitrary objects" do
it "sorts a hash of MyObject objects" do
my_objects = {
first: MyObject.new('bob', 6), # An object with size 6
second: MyObject.new('joe', 5), # An object with size 5
third: MyObject.new('bill', 4) # An object with size 4
}
sorted = my_objects.sort_by { |k,v| v} # Uses MyObject::<=>
expect(Hash[*sorted.flatten].keys).to eql [:third, :second, :first]
sorted = my_objects.sort_by { |k,v| v.name}
expect(Hash[*sorted.flatten].keys).to eql [:third, :first, :second]
end
it "sorts an array of MyObject objects" do
my_objects = [
MyObject.new('first', 6), # An object with size 6
MyObject.new('second', 5), # An object with size 5
MyObject.new('third', 4) # An object with size 4
]
expect(my_objects.map{ |i| i.name }).to eql ['first', 'second', 'third']
sorted = my_objects.sort
expect(sorted.map{ |i| i.size }).to eql [4 ,5, 6]
expect(sorted.map{ |i| i.name }).to eql ['third', 'second', 'first']
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment