我有一系列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)时间。有人可以告诉我最有效的排序方式吗?
答案 0 :(得分:68)
如果有什么比明显的方式快得多,我会感到惊讶:
a2.sort_by{|x| a1.index x.id}
答案 1 :(得分:26)
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)
答案 2 :(得分:16)
我喜欢接受的答案,但在ActiveSupport中有index_by,这使得创建初始哈希变得更加容易。见Cleanest way to create a Hash from an Array
实际上你可以在一行中完成这个,因为Enumerable也支持index_by:
a2.index_by(&:id).values_at(*a1)
答案 3 :(得分:7)
受Eric Woodruff's Answer的启发,我提出了以下vanilla Ruby解决方案:
a2.group_by(&:object_id).values_at(*a1).flatten(1)
方法文档: