Skip to content

Instantly share code, notes, and snippets.

@apeiros
Created April 1, 2011 12:10
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 apeiros/898050 to your computer and use it in GitHub Desktop.
Save apeiros/898050 to your computer and use it in GitHub Desktop.
sort_by with asc/desc
## sortby.rb
module SortBy
class Reverse
include Comparable
attr_reader :value
def initialize(value)
@value = value
end
def <=>(other)
other.value <=> @value
end
end
class Lazy
def initialize(&block)
@block = block
@memo = false
@value = nil
end
def value
@memo ? @value : (@value = @block[])
end
def <=>(other)
value <=> other.value
end
end
def asc(value=nil, &lazy)
lazy ? SortBy::Lazy.new(&lazy) : value
end
def desc(value=nil, &lazy)
value = SortBy::Lazy.new(&lazy) if lazy
SortBy::Reverse.new(value)
end
module_function :asc, :desc
end
## sortby/convenience.rb
module Kernel
def asc(value=nil, &lazy)
lazy ? SortBy::Lazy.new(&lazy) : value
end
def desc(value=nil, &lazy)
value = SortBy::Lazy.new(&lazy) if lazy
SortBy::Reverse.new(value)
end
module_function :asc, :desc
end
## usage
if __FILE__ == $PROGRAM_NAME then
require 'pp'
Person = Struct.new(:first_name, :last_name, :age)
people = [
Person.new('Peter', 'Pan', 23),
Person.new('Peter', 'Pan', 15),
Person.new('Peter', 'Parker', 15),
]
pp people.sort_by { |person| [asc(person.first_name), asc(person.last_name), desc(person.age)] }
Foo = Struct.new(:a, :b, :c)
calc = proc { |s,x| sleep(s); x }
foos = [
Foo.new(1,2,1),
Foo.new(1,2,2),
Foo.new(1,3,4),
Foo.new(2,3,4),
]
start = Time.now
pp foos.sort_by { |x| [asc(x.a), desc(calc[0.1, x.b]), asc(calc[0.2, x.c])] }
stop = Time.now
printf "Elapsed: %.2fs\n", stop-start
start = Time.now
pp foos.sort_by { |x| [asc(x.a), desc { calc[0.1, x.b] }, asc { calc[0.2, x.c] }] }
stop = Time.now
printf "Elapsed: %.2fs\n", stop-start
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment