optimized compare_absolute method
This commit is contained in:
parent
f83703c6af
commit
9e2b2e2abb
|
@ -68,37 +68,49 @@ class Bdb::Simple
|
||||||
@db = nil
|
@db = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
CLASS_ORDER = {}
|
||||||
|
[FalseClass, TrueClass, Fixnum, Numeric, Float, Symbol, String, Array].each_with_index {|c, i| CLASS_ORDER[c] = i}
|
||||||
|
|
||||||
def self.compare_absolute(left, right)
|
def self.compare_absolute(left, right)
|
||||||
if left.class == right.class
|
if left.is_a?(right.class)
|
||||||
if left.is_a?(Array) and right.is_a?(Array)
|
case left
|
||||||
|
when Array
|
||||||
# Arrays: compare one element at a time.
|
# Arrays: compare one element at a time.
|
||||||
left.zip(right) do |l,r|
|
n = [left.size, right.size].min
|
||||||
comp = compare_absolute(l, r)
|
n.times do |i|
|
||||||
return comp unless comp == 0
|
comp = compare_absolute(left[i], right[i])
|
||||||
|
return comp if comp != 0
|
||||||
end
|
end
|
||||||
left.size == right.size ? 0 : -1
|
left.size <=> right.size
|
||||||
elsif left.is_a?(Hash) and right.is_a?(Hash)
|
when Hash
|
||||||
# Hashes: sort the keys and compare as an array of arrays.
|
# Hashes: sort the keys and compare as an array of arrays. This may be slow.
|
||||||
left = left.to_a.sort {|a,b| compare_absolute(a[0],b[0])}
|
left = left.to_a.sort {|a,b| compare_absolute(a[0],b[0])}
|
||||||
right = right.to_a.sort {|a,b| compare_absolute(a[0],b[0])}
|
right = right.to_a.sort {|a,b| compare_absolute(a[0],b[0])}
|
||||||
compare_absolute(left, right)
|
compare_absolute(left, right)
|
||||||
|
when NilClass, TrueClass, FalseClass
|
||||||
|
0
|
||||||
|
when Symbol
|
||||||
|
left.to_s <=> right.to_s
|
||||||
else
|
else
|
||||||
begin
|
# Use the spaceship operator.
|
||||||
# Try to use the spaceship operator.
|
left <=> right
|
||||||
left <=> right
|
|
||||||
rescue NoMethodError => e
|
|
||||||
left.hash <=> right.hash
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
elsif left.kind_of?(Numeric) and right.kind_of?(Numeric)
|
||||||
|
# Numerics are always comparable.
|
||||||
|
left <=> right
|
||||||
else
|
else
|
||||||
# Nil is the smallest. Hash is the largest. All other objects are sorted by class name.
|
# Nil is the smallest. Hash is the largest.
|
||||||
return -1 if left.is_a?(NilClass)
|
return -1 if left.is_a?(NilClass) or right.is_a?(Hash)
|
||||||
return 1 if right.is_a?(NilClass)
|
return 1 if left.is_a?(Hash) or right.is_a?(NilClass)
|
||||||
return 1 if left.is_a?(Hash)
|
|
||||||
return -1 if right.is_a?(Hash)
|
|
||||||
|
|
||||||
# Compare class names and hashes as a last resort if that fails.
|
# Try to use the class sort order so we don't have to do a string comparison.
|
||||||
right.class.name <=> left.class.name
|
left_order = CLASS_ORDER[left.class]
|
||||||
|
right_order = CLASS_ORDER[right.class]
|
||||||
|
if left_order.nil? and right_order.nil?
|
||||||
|
left.class.name <=> right.class.name
|
||||||
|
else
|
||||||
|
(left_order || 9999) <=> (right_order || 9999)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,7 +44,7 @@ class SimpleTest < Test::Unit::TestCase
|
||||||
def test_compare_absolute
|
def test_compare_absolute
|
||||||
list = [5, 6, "foo", :bar, "bar", :foo, [1,2,4], true, [1,2,3], false, [1], [2], nil, {}, {:b => 1, :a => 1}, {:b => 2, :a => 1}]
|
list = [5, 6, "foo", :bar, "bar", :foo, [1,2,4], true, [1,2,3], false, [1], [2], nil, {}, {:b => 1, :a => 1}, {:b => 2, :a => 1}]
|
||||||
|
|
||||||
expected = [nil, true, :bar, :foo, "bar", "foo", 5, 6, false, [1], [1, 2, 3], [1, 2, 4], [2], {}, {:a=>1, :b=>1}, {:a=>1, :b=>2}]
|
expected = [nil, false, true, 5, 6, :bar, :foo, "bar", "foo", [1], [1, 2, 3], [1, 2, 4], [2], {}, {:a=>1, :b=>1}, {:a=>1, :b=>2}]
|
||||||
assert_equal expected, list.sort {|a,b| Bdb::Simple.compare_absolute(a,b)}
|
assert_equal expected, list.sort {|a,b| Bdb::Simple.compare_absolute(a,b)}
|
||||||
100.times do
|
100.times do
|
||||||
assert_equal expected, list.shuffle.sort {|a,b| Bdb::Simple.compare_absolute(a,b)}
|
assert_equal expected, list.shuffle.sort {|a,b| Bdb::Simple.compare_absolute(a,b)}
|
||||||
|
|
Loading…
Reference in a new issue