由于您知道所需的顺序,因此无需对数组进行排序。这是您可以做到这一点的一种方法。 (我已将您的哈希数组称为 bible。)
bible.group_by { |h| h[:book] }.values_at(*array).flatten
#=> [{:book=>"Matthew", :chapter=>"4", :section=>"new_testament"},
# {:book=>"Matthew", :chapter=>"22", :section=>"new_testament"},
# {:book=>"Mark", :chapter=>"6", :section=>"new_testament"},
# {:book=>"Acts", :chapter=>"9", :section=>"new_testament"},
# {:book=>"Acts", :chapter=>"17", :section=>"new_testament"},
# {:book=>"1John", :chapter=>"1", :section=>"new_testament"},
# {:book=>"1John", :chapter=>"1", :section=>"new_testament"}]
由于Enumerable#group_by、Hash#values_at 和Array#flatten 都只需要遍历数组bible,这可能比bible 很大时的排序要快。
这里是步骤。
h = bible.group_by { |h| h[:book] }
#=> {"Matthew"=>[{:book=>"Matthew", :chapter=>"4", :section=>"new_testament"},
# {:book=>"Matthew", :chapter=>"22", :section=>"new_testament"}],
# "Mark" =>[{:book=>"Mark", :chapter=>"6", :section=>"new_testament"}],
# "1John" =>[{:book=>"1John", :chapter=>"1", :section=>"new_testament"},
# {:book=>"1John", :chapter=>"1", :section=>"new_testament"}],
# "Acts" =>[{:book=>"Acts", :chapter=>"9", :section=>"new_testament"},
# {:book=>"Acts", :chapter=>"17", :section=>"new_testament"}]
# }
a = h.values_at(*array)
#=> h.values_at('Matthew', 'Mark', 'Acts', '1John')
#=> [[{:book=>"Matthew", :chapter=>"4", :section=>"new_testament"},
# {:book=>"Matthew", :chapter=>"22", :section=>"new_testament"}],
# [{:book=>"Mark", :chapter=>"6", :section=>"new_testament"}],
# [{:book=>"Acts", :chapter=>"9", :section=>"new_testament"},
# {:book=>"Acts", :chapter=>"17", :section=>"new_testament"}],
# [{:book=>"1John", :chapter=>"1", :section=>"new_testament"},
# {:book=>"1John", :chapter=>"1", :section=>"new_testament"}]]
最后,a.flatten 返回前面显示的数组。
让我们做一个基准测试。
require 'fruity'
@bible = [
{:book=>"Matthew",
:chapter=>"4",
:section=>"new_testament"},
{:book=>"Matthew",
:chapter=>"22",
:section=>"new_testament"},
{:book=>"Mark",
:chapter=>"6",
:section=>"new_testament"},
{:book=>"1John",
:chapter=>"1",
:section=>"new_testament"},
{:book=>"1John",
:chapter=>"1",
:section=>"new_testament"},
{:book=>"Acts",
:chapter=>"9",
:section=>"new_testament"},
{:book=>"Acts",
:chapter=>"17",
:section=>"new_testament"}]
@order = ['Matthew', 'Mark', 'Acts', '1John']
def bench_em(n)
arr = (@bible*((n/@bible.size.to_f).ceil))[0,n].shuffle
puts "arr contains #{n} elements"
compare do
_sort { arr.sort { |h1,h2| @order.index(h1[:book]) <=>
@order.index(h2[:book]) }.size }
_sort_by { arr.sort_by { |h| @order.find_index(h[:book]) }.size }
_sort_by_with_hash {ord=@order.each.with_index.to_h;
arr.sort_by {|b| ord[b[:book]]}.size}
_values_at { arr.group_by { |h| h[:book] }.values_at(*@order).flatten.size }
end
end
@maxpleaner、@ChaitanyaKale 和@Michael Kohl 分别贡献了_sort、_sort_by 和sort_by_with_hash。
bench_em 100
arr contains 100 elements
Running each test 128 times. Test will take about 1 second.
_sort_by is similar to _sort_by_with_hash
_sort_by_with_hash is similar to _values_at
_values_at is faster than _sort by 2x ± 1.0
bench_em 1_000
arr contains 1000 elements
Running each test 16 times. Test will take about 1 second.
_sort_by_with_hash is similar to _values_at
_values_at is similar to _sort_by
_sort_by is faster than _sort by 2x ± 0.1
bench_em 10_000
arr contains 10000 elements
Running each test once. Test will take about 1 second.
_values_at is faster than _sort_by_with_hash by 10.000000000000009% ± 10.0%
_sort_by_with_hash is faster than _sort_by by 10.000000000000009% ± 10.0%
_sort_by is faster than _sort by 2x ± 0.1
bench_em 100_000
arr contains 100000 elements
Running each test once. Test will take about 3 seconds.
_values_at is similar to _sort_by_with_hash
_sort_by_with_hash is similar to _sort_by
_sort_by is faster than _sort by 2x ± 0.1
这是第二次运行。
bench_em 100
arr contains 100 elements
Running each test 128 times. Test will take about 1 second.
_sort_by_with_hash is similar to _values_at
_values_at is similar to _sort_by
_sort_by is faster than _sort by 2x ± 0.1
bench_em 1_000
arr contains 1000 elements
Running each test 8 times. Test will take about 1 second.
_values_at is faster than _sort_by_with_hash by 10.000000000000009% ± 10.0%
_sort_by_with_hash is similar to _sort_by
_sort_by is faster than _sort by 2.2x ± 0.1
bench_em 10_000
arr contains 10000 elements
Running each test once. Test will take about 1 second.
_values_at is similar to _sort_by_with_hash
_sort_by_with_hash is similar to _sort_by
_sort_by is faster than _sort by 2x ± 1.0
bench_em 100_000
arr contains 100000 elements
Running each test once. Test will take about 3 seconds.
_sort_by_with_hash is similar to _values_at
_values_at is similar to _sort_by
_sort_by is faster than _sort by 2x ± 0.1