0

I have an array

a = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

and another array:

b = [0, 3, 6, 3, 4, 0, 1]

Is it possible to sort array a according to values in array b?

The result should be:

a = ['c', 'e', 'b', 'd', 'g', 'a', 'f']

Something like this doesn't seem to exist in Ruby/Rails:

a.sort_with_index{ |elem, index| b[index] }

Edit: in response to the duplicate marking: the question being referred to has an array with elements having an ID, and the other array references the ID's directly. This is not the same, and the same solution will not apply...

rept
  • 2,086
  • 1
  • 26
  • 44
  • Well, of course it's *possible*. It's a question of what's the cleanest, simplest way. `a.sort_by {|x| -b[a.index x] }` perhaps. – lurker Sep 26 '17 at 16:50
  • Another way: `a.values_at(*a.each_index.sort_by { |i| -b[i] }) #=> ["c", "e", "b", "d", "g", "a", "f"]`. – Cary Swoveland Sep 26 '17 at 19:08
  • This is a pure-Ruby question so it should not have a Rails tag. That tag could be a small time-waster for readers only interested in Rails questions, but more importantly, readers who filter-out Rails questions might miss the opportunity to post a great answer. – Cary Swoveland Sep 26 '17 at 22:36

2 Answers2

3
a.sort_by.with_index { |_,i| [-b[i], i] }
  #=> ["c", "e", "b", "d", "g", "a", "f"]

This uses the indices of elements in a to break ties. I see from a comment on @tadman's answer that that is desired, though it is not a requirement given in the statement of the question. See the third paragraph of the doc for Array#<=> for an explanation of how arrays are ordered in sorting operations.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
1

You can just combine the two, sort, and strip out the original a values:

a.zip(b).sort_by { |_a, _b| -_b }.map { |_a,_| _a }
tadman
  • 208,517
  • 23
  • 234
  • 262
  • 3
    ...or `a.zip(b).sort_by(&:last).map(&:first).reverse #=> ["c", "e", "d", "b", "g", "f", "a"]` – Cary Swoveland Sep 26 '17 at 19:11
  • It's close, but with duplicates the original order should precede. That's why the result should be: ['c', 'e', 'b', 'd', 'g', 'a', 'f'] – rept Sep 26 '17 at 20:50
  • 1
    @rept That's a secondary sort consideration, but you didn't communicate that clearly in your question. – tadman Sep 26 '17 at 21:02