Sorting an Array of hashes based on an Array of so

2019-08-06 13:57发布

问题:

I have an array of hashes as given below:

user_quizzes = [{:id => 3897, :quiz_id => 1793, :user_id => 252}, {:id => 3897, :quiz_id => 1793, :user_id => 475}, {:id => 3897, :quiz_id => 1793, :user_id => 880}, {:id => 3897, :quiz_id => 1793, :user_id => 881}, {:id => 3897, :quiz_id => 1793, :user_id => 882}, {:id => 3897, :quiz_id => 1793, :user_id => 883}, {:id => 3897, :quiz_id => 1793, :user_id => 884}]

Also, based on a particular condition I took the values of 'user_id' key from the same hash and sorted it and the same array is given below:

sorted_user_ids = [880, 881, 882, 883, 884, 475, 252]

Now, I need the user_quizzes to be rearranged based on the order of user_id in sorted_user_ids array.

Can anyone please help me on this. :)

回答1:

Using Enumerable#sort_by or Array#sort_by!, you can specify the key that will be used for comparison:

user_quizzes = [
  {:id => 3897, :quiz_id => 1793, :user_id => 252},
  {:id => 3897, :quiz_id => 1793, :user_id => 475},
  {:id => 3897, :quiz_id => 1793, :user_id => 880},
  {:id => 3897, :quiz_id => 1793, :user_id => 881},
  {:id => 3897, :quiz_id => 1793, :user_id => 882},
  {:id => 3897, :quiz_id => 1793, :user_id => 883},
  {:id => 3897, :quiz_id => 1793, :user_id => 884}
]
sorted_user_ids = [880, 881, 882, 883, 884, 475, 252]
user_quizzes.sort_by { |x| sorted_user_ids.index(x[:user_id]) }
# => [{:id=>3897, :quiz_id=>1793, :user_id=>880},
#     {:id=>3897, :quiz_id=>1793, :user_id=>881},
#     {:id=>3897, :quiz_id=>1793, :user_id=>882},
#     {:id=>3897, :quiz_id=>1793, :user_id=>883},
#     {:id=>3897, :quiz_id=>1793, :user_id=>884},
#     {:id=>3897, :quiz_id=>1793, :user_id=>475},
#     {:id=>3897, :quiz_id=>1793, :user_id=>252}]

Side note: sorted_user_ids.index(x[:user_id]) can become bottleneck (repeat O(n) operations), if the array is huge.

Build a hash that maps user_ids to orders in such case:

sorted_user_ids = [880, 881, 882, 883, 884, 475, 252]
order = Hash[sorted_user_ids.each_with_index.to_a]
# => {880=>0, 881=>1, 882=>2, 883=>3, 884=>4, 475=>5, 252=>6}
user_quizzes.sort_by { |x| order[x[:user_id]] }
# => same as above.