Here's another wordy way to do it:
order = [:col1, :col2, :col3]
cols = [:col3, :col2, :col5, :col4]
sorted_order = cols.sort_by do |c|
if order.index(c)
[1, order.index(c)]
else
[2, cols.index(c)]
end
end
p sorted_order # => [:col2, :col3, :col5, :col4]
Here's how it works. sort_by yields elements of an array to the block; the block should then return something comparable (technically, something that responds to the <=> operator). sort_by uses the <=> operator on the results returned by the block to decide what order the array should be in.
The <=> (spaceship) operator, as you may know, is a binary operator taking two elements a and b. If a < b, it returns -1. If a == b, it returns 0. If a > b, it returns +1.
Arrays respond in an unsurprising way to the <=> operator. The elements of the left array are compared with the elements of the right array in turn, starting with index 0 and increasing. If the a[i] <=> b[i] is != 0, return that result, but if the result is 0, examine the next element. If the last pair of elements compared is 0 (equal) and the arrays are the same size, the arrays are equal and Array.<=> returns 0, otherwise the longer array is considered larger (this example always returns equal size arrays, however).
So, for example:
[2, 1] <=> [2, 2] == -1
[2, 2] <=> [2, 2] == 0
[2, 3] <=> [2, 2] == +1
[1, 2] <=> [2, 1] == +1
So, inside a sort_by, we can use the elements of an array a to indicate primary, secondary, tertiary etc. sort order. a[0] is the primary sort order, a[1] is the secondary sort order, and so on.
All of the columns the customer specified should come first. So, for each column, find its index in customer specified order (order
). If that returns a number, then we know that the customer specified that column, and we know its index in the customer-specified list. The primary sort order is 1, because we want the customer specified columns to come first; the secondary sort order is the index, since that gives us the order the customer specified the columns.
If we don't find the column in the order array (that is, order.index(c) returns nil), then we'll 2 as the primary sort order and the index in the master column list (cols
) as the secondary sort order. That way all columns the customer did not specify will be last, but in the order they are specified in the laster column list.