44

我有一个 id 数组

a1 = [1, 2, 3, 4, 5]  

我有另一个对象数组,其 id 以随机顺序排列

a2 = [(obj_with_id_5), (obj_with_id_2), (obj_with_id_1), (obj_with_id_3), (obj_with_id_4)]  

现在我需要根据 a1 中 id 的顺序对 a2 进行排序。所以 a2 现在应该变成:

[(obj_with_id_1), (id_2), (id_3), (id_4), (id_5)]  

a1 可能是 [3, 2, 5, 4, 1] 或任何顺序,但 a2 应对应于 a1 中 id 的顺序。

我喜欢这样:

a1.each_with_index do |id, idx|
  found_idx = a1.find_index { |c| c.id == id }
  replace_elem = a2[found_idx]
  a2[found_idx] = a2[idx]
  a2[idx] = replace_elem
end  

但是,如果 a2 的元素顺序与 a1 完全相反,这仍然可能会遇到 O(n^2) 时间。有人可以告诉我排序a2的最有效方法吗?

4

4 回答 4

86

如果有什么比明显的方式快得多,我会感到惊讶:

a2.sort_by{|x| a1.index x.id}
于 2012-08-15T05:04:43.360 回答
27
hash_object = objects.each_with_object({}) do |obj, hash| 
  hash[obj.object_id] = obj
end

[1, 2, 3, 4, 5].map { |index| hash_object[index] }
#=> array of objects in id's order

我相信运行时间将是 O(n)

于 2012-08-14T22:34:32.190 回答
19

我喜欢接受的答案,但在 ActiveSupport 中有 index_by,它使创建初始哈希变得更加容易。请参阅从数组创建哈希的最简洁方法

事实上,你可以在一行中做到这一点,因为 Enumerable 也支持 index_by :

a2.index_by(&:id).values_at(*a1)
于 2014-08-13T22:51:08.793 回答
7

Eric Woodruff's Answer 的启发,我提出了以下香草 Ruby 解决方案:

a2.group_by(&:object_id).values_at(*a1).flatten(1)

方法文档:

于 2014-11-07T21:06:55.537 回答