def sort(arr, crit, i)
final = []
arr = arr.sort_by {|a| a.send(crit[i])}
hash = arr.slice_into_groups(crit[i])
sorted_keys = hash.sort_by {|k, v| k}.gimme_firsts
if i < crit.size - 1
sorted_keys.each do |key|
final << sort(hash[key], crit, i+1)
end
else
final = arr
end
return final.flatten
end
class Array
def slice_into_groups(crit)
hash = {}
self.each do |a|
hash[a.send(crit)] = [] if hash[a.send(crit)].blank?
hash[a.send(crit)] << a
end
hash
end
def gimme_firsts
self.collect{|a| a.first}
end
And Tests for the Array code.
class ArrayTest < Test::Unit::TestCase
def test_slice_into_groups
objects = Model.find(:all)
assert_not_nil objects.size
old_size = objects.size
grouped_objects = objects.slice_into_groups('attribute')
sum = 0
grouped_objects.each do |k, v|
sum += v.size
v.each do |obj|
assert_equal k, obj.attribute
end
end
assert_equal old_size, sum
end
def test_gimme_firsts
assert_equal [1, 2, 3, 4, 5, 6, 7], [[1, 2, 3],[2, 2, 3],[3, 2, 3],[4, 2, 3],[5, 2, 3],[6, 2, 3],[7, 2, 3]].gimme_firsts
end
end
This is basically to keep tests in place for MySQL order bys ... which I know make absolutely no sense, but if there's a requirement and someone changes something I like a test to break to tell them I didn't put the order by in there for nothing.
The index passing down the call stack is fairly ugly but I need to find a better way.
"Open your eyes"
Metallica - Invisible Kid.
0 Responses to Sorting an array of ActiveRecord objects on multiple attributes
Something to say?