views:

54

answers:

2

I have a ruby array that looks something like this:

my_array = ['mushroom', 'beef', 'fish', 'chicken', 'tofu', 'lamb']

I want to sort the array so that 'chicken' and 'beef' are the first two items, then the remaining items are sorted alphabetically. How would I go about doing this?

+1  A: 
irb> my_array.sort_by { |e| [ e == 'chicken' ? 0 : e == 'beef' ? 1 : 2, e ] }
 #=> ["chicken", "beef", "fish", "lamb", "mushroom", "tofu"]

This will create a sorting key for each element of the array, and then sort the array elements by their sorting keys. Since the sorting key is an array, it compares by position, so [0, 'chicken'] < [1, 'beef'] < [2, 'apple' ] < [2, 'banana'].

If you don't know what elements you wanted sorted to the front until runtime, you can still use this trick:

 irb> promotables = [ 'chicken', 'beef' ]
  #=> [ 'chicken', 'beef' ]
 irb> my_array.sort_by { |e| [ promotables.index(e) || promotables.size, e ] }
  #=> ["chicken", "beef", "fish", "lamb", "mushroom", "tofu"]
 irb> promotables = [ 'tofu', 'mushroom' ]
  #=> [ 'tofu', 'mushroom' ]
 irb> my_array.sort_by { |e| [ promotables.index(e) || promotables.size, e ] }
  #=> [ "tofu", "mushroom", "beef", "chicken", "fish", "lamb"]
rampion
A: 

Mine's a lot more generic and more useful if you get your data only at runtime.

my_array = ['mushroom', 'beef', 'fish', 'chicken', 'tofu', 'lamb']
starters = ['chicken', 'beef']
starters + (my_array.sort - starters)
# => ["chicken", "beef" "fish", "lamb", "mushroom", "tofu"]
Thomas R. Koll
if 'chicken' or 'beef' occur more (or less) than once in `my_array` then the result of this will not be a reordering of `my_array`.
rampion