Sorting an array of objects based on an ordered list of identifiers

I have a set of @users objects, each of which has its id attribute.

 @users = [#<User id:1>, #<User id:2>] 

I also have an ordered ids array.

 ids = [2,1] 

ΒΏIs there a magical way to sort the collection using this list of identifiers? Do not make another call to the database if possible.

Thanks!!!

+8
sorting ruby ruby-on-rails
source share
4 answers

Try it. First create a backward mapping with id -> user.

 ids_users = {} @users.each {|user| ids_users[user.id] = user} 

Then use the ids order

 ids.collect{ |id| ids_users[id] } 
+11
source share

In fact, you do not need to sort, build an intermediate indexed hash, this is O (n):

 users_by_id = Hash[@users.map { |u| [u.id, u] }] users_by_id.values_at(*ids) 

If you still want to try the sorting approach, the Schwartz transform) will be adequate:

 @users.sort_by { |u| ids.index(u.id) } 

However, using index inside a loop is a red flag: O (n ^ 2). We can build an intermediate hash to return to O (n * log n):

 indexes = Hash[ids.each_with_index.to_a] @users.sort_by { |u| indexes[u.id] } 
+18
source share

Of course, you don’t need to go to the database, since you already have User objects, although since users are in the array, you probably want to create a temporary map id => User to get the final result.

+1
source share

If you can access the identifier of each user by calling user.id, you can sort the array as follows:

 @users.sort!{|a,b| a.id <=> b.id } 

If you only have identifiers in a separate array of objects, you can do the following: Replace the two arrays together, sort the resulting array by identifiers, and then collect the sorted users from the result.

 users_ids = @users.zip(ids) # creates an array of smaller arrays each holding [user, id] users_ids.sort!{|a,b| a[1] <=> b[1]} # sorts on the id in each sub-array sorted_users = users_ids.collect{|item| item[0]} #grabs the users, leaving the ids behind 

Take a look at this: http://ariejan.net/2007/01/28/ruby-sort-an-array-of-objects-by-an-attribute

0
source share

All Articles