根据另一个数组的元素对数组进行排序

Ari*_*N3o 39 ruby arrays sorting algorithm

我有一系列的ID

a1 = [1, 2, 3, 4, 5]  
Run Code Online (Sandbox Code Playgroud)

我有另一个对象数组,其中id为随机顺序

a2 = [(obj_with_id_5), (obj_with_id_2), (obj_with_id_1), (obj_with_id_3), (obj_with_id_4)]  
Run Code Online (Sandbox Code Playgroud)

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

[(obj_with_id_1), (id_2), (id_3), (id_4), (id_5)]  
Run Code Online (Sandbox Code Playgroud)

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  
Run Code Online (Sandbox Code Playgroud)

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

pgu*_*rio 72

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

a2.sort_by{|x| a1.index x.id}
Run Code Online (Sandbox Code Playgroud)

  • 这种方法也很快,但使用哈希就像比光速更快.我用两种方法对10,000个数字进行了测试(仅仅是为了测试).你的方法平均花费了1.3秒,但是使用哈希平均需要花费0.01秒. (6认同)

meg*_*gas 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
Run Code Online (Sandbox Code Playgroud)

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

  • 是的,你是对的,我会第二次同意你的看法. (7认同)
  • 我不同意,建立哈希表需要O(n),请看这里http://en.wikipedia.org/wiki/Hash_table (2认同)
  • 是的,构建哈希表是O(n)时间.排序是O(n)时间.所以你有2xO(n)...嗯...这将小于n ^ 2.我纠正了.接得好! (2认同)

Eri*_*uff 17

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

实际上你可以在一行中完成这个,因为Enumerable也支持index_by:

a2.index_by(&:id).values_at(*a1)
Run Code Online (Sandbox Code Playgroud)


Aje*_*i32 7

Eric Woodruff的回答启发,我提出了以下vanilla Ruby解决方案:

a2.group_by(&:object_id).values_at(*a1).flatten(1)
Run Code Online (Sandbox Code Playgroud)

方法文档: