按类别名称对数组进行排序

Sorting an array by category names

给定这个数组 a:

a = [
    {id: 3, category_name: "Horror"},
    {id: 4, category_name: "Non-Fiction"},
    {id: 5, category_name: "LGBT"},
    {id: 6, category_name: "Romance"},
    {id: 7, category_name: "Romance"}
]

我想要一种使用数组顺序(索引)按类别名称对数组 a 中的对象进行排序的方法,幸运的是 Ruby 数组默认是有序数组:

categories_sorted = [
   "Romance",
   "LGBT",
   "Non-Fiction",
   "Horror"
]

这样排序算法就会给我一个如下所示的数组:

result = [
    {id: 6, category_name: "Romance"},
    {id: 7, category_name: "Romance"},
    {id: 5, category_name: "LGBT"},
    {id: 4, category_name: "Non-Fiction"},
    {id: 3, category_name: "Horror"}
]

您能指出有效实现此目标的任何方法吗? 数组 "a" 可以大到 20 个对象,而排序的类别在我的场景中可以有多达 30 个类别。

做如下:-

a = [
    {id: 3, category_name: "Horror"},
    {id: 4, category_name: "Non-Fiction"},
    {id: 5, category_name: "LGBT"},
    {id: 6, category_name: "Romance"},
    {id: 7, category_name: "Romance"}
]

categories_sorted = [
   "Romance",
   "LGBT",
   "Non-Fiction",
   "Horror"
]

p a.sort_by { |h| [categories_sorted.index(h[:category_name]), h[:id]] }
# >> [{:id=>6, :category_name=>"Romance"}, {:id=>7, :category_name=>"Romance"}, {:id=>5, :category_name=>"LGBT"}, {:id=>4, :category_name=>"Non-Fiction"}, {:id=>3, :category_name=>"Horror"}]

值得编制一个排序索引列表以避免必须不断查找:

categories_sorted_index = Hash[
  categories_sorted.each_with_index.collect do |name, index|
    [ name, index ]
  end
]

a.sort_by do |entry|
  categories_sorted_index[entry[:category_name]] || 0
end

# =>
# {:id=>7, :category_name=>"Romance"}
# {:id=>6, :category_name=>"Romance"}
# {:id=>5, :category_name=>"LGBT"}
# {:id=>4, :category_name=>"Non-Fiction"}
# {:id=>3, :category_name=>"Horror"}

这里有一个使用Enumerable#group_by and Hash#values_at rather than Enumerable#sort_by的方法:

a.group_by { |h| h[:category_name] }.values_at(*categories_sorted).flatten
  #=> [{:id=>6, :category_name=>"Romance"},
  #    {:id=>7, :category_name=>"Romance"},
  #    {:id=>5, :category_name=>"LGBT"},
  #    {:id=>4, :category_name=>"Non-Fiction"},
  #    {:id=>3, :category_name=>"Horror"}]