0

I've got an array of objects which I pull from the database. But I can sort them only in ascending or descending order from database, however I need them in custom order.

Let's say I have an array of objects from db :

arr =  [obj1,obj2,obj3]

where obj1 has id 1, obj2 has id 2 and obj3 has id 3

but my sort order would be 3,1,2 or I'd have some array of ids which would dictate the order i.e [3,1,2]

So the order of custom sorting would be :

arr =  [obj3,obj1,obj2]

I've tried :

arr.sort_by{|a,b| [3,1,2]}

I've been reading some tutorials and links about sorting and it's mostly simple sorting. So how would one achieve the custom sorting described above?

2 Answers 2

4

You're close. [3,1,2] specifies an ordering, but it doesn't tell the block how to relate it to your objects. You want something like:

arr.sort_by {|obj| [3,1,2].index(obj.id) }

So the comparison will order your objects sequentially by the position of their id in the array.

Or, to use the more explicit sort (which you seem to have sort_by slightly confused with):

arr.sort do |a,b|
  ordering = [3,1,2]
  ordering.index(a.id) <=> ordering.index(b.id)
end
Sign up to request clarification or add additional context in comments.

3 Comments

The performance of this sort is likely to be O(n^2 log n), which is very very bad performance.
@yfeldblum: That is true and a good point, but for a case like this where you have a handful of elements you're ordering "by hand," the asymptotic behavior of the algorithm is not important — to wit, n is a constant when you'll only ever work with three elements, meaning any algorithm turns into O(1). Constant factors like computing and allocating a hash are likely to dominate your real-world performance with such small datasets.
That is absolutely true with small datasets such as the one given in the questioner's example. My concern is twofold: (1) what if the dataset is larger than the example given and large enough to make this a real issue? and (2) it's good to provide examples of techniques that are fast in the larger cases so that other people can see what issues there are to think about and how to solve them.
2

This is like @Chuck's answer, but with O(n log n) performance.

# the fixed ordering
ordering = [3, 1, 2]

# a map from the object to its position in the ordering
ordering_index = Hash[ordering.map(&:id).each_with_index.to_a]

# a fast version of the block
arr.sort_by{|obj| ordering_index[obj.id]}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.