BobRodes
BobRodes

Reputation: 6165

Problems using `elsif` in a `sort` block

I have this array:

ary = [[1, 6, 7], [1, 4, 9], [1, 8, 3]]

I want to sort it by the first odd number, or the last number if they are all even, in each subarray.

Since the first element in each array is the same object 1 for this particular ary, I can solve this like this:

ary2 = ary.sort_by { |a, b, c| b.odd? ? b : c }

But when I try a more general one:

arr2 = ary.sort_by { |a, b, c| a.odd? ? a : b.odd? ? b : c }

ary2 comes back unsorted.

I tried removing the ternary operators like this:

ary2 = ary.sort_by do |a, b, c|
  if a.odd? 
    a
  elsif b.odd?
    b
  else
    c
  end
end

with the same effect (i.e., none).

Is there some reason that elsif can't be used in blocks passed to the sort_by method?


Edit: Axiac pointed out the problem with my logic. It looks like conditional logic has to deal with all of the possible permutations of odd and even values. This works:

arr2 = arr.sort_by do |a, b, c| 
  if a.odd?
    if b.odd?
      if c.odd?
        [a, b, c]
      else
        [a, b]
      end
    elsif c.odd?
      [a, c]
    else
      a
    end
  elsif b.odd?
    if c.odd?
      [b, c]
    else
      b
    end
  else
    c
  end
end

Maybe there's a more succinct and less brittle way to do it, but it's probably a good idea to do it this way instead:

arr2 = arr.sort_by do |sub_arr|
  temp = sub_arr.select do |e|
    e.odd?
  end
  temp.empty? ? Array(sub_arr.last) : temp
end

I'll see myself out.

Upvotes: 0

Views: 93

Answers (2)

sawa
sawa

Reputation: 168179

Regarding your original question, just as axiac points out in the comment, the result of the sorting should be exactly the same as the input array because they are all sorted by the first odd element in each subarray, which is 1, and the sort method is stable in MRI.


Regarding your question after the edit, my answer would be:

ary.sort_by{|a| a[0...-1].select(&:odd?) << a.last}
# => [[1, 8, 3], [1, 6, 7], [1, 4, 9]]

I am pretty confident that this is what you wrote after the edit that you wanted, but I am not sure if this is what you wanted since the sorting mechanism looks strange to me.

Upvotes: 2

Cary Swoveland
Cary Swoveland

Reputation: 110725

I find the statement of the question ambiguous. I will give an answer that is consist with one interpretation. If that is not what you want, please clarify hte question.

def my_sort(arr)
  arr.sort_by {|a| a.any?(&:odd?) ? a.map {|e| e.odd? ? e : Float::INFINITY} : [a.last]}
end

my_sort [[1, 6, 7], [1, 4, 9], [1, 2, 3]]
  #=>   [[1, ∞, 7], [1, ∞, 9], [1, ∞, 3]] (sort_by)
  #=>   [[1, 2, 3], [1, 6, 7], [1, 4, 9]]
my_sort [[3, 6, 7], [4, 1, 9], [5, 8, 1]]
  #=>   [[3, ∞, 7], [∞, 1, 9], [5, ∞, 1]] (sort_by) 
  #=>   [[3, 6, 7], [5, 8, 1], [4, 1, 9]] 
my_sort [[2, 6, 8], [4, 1, 4], [8, 6, 2]]
  #=>   [[8],       [∞, 1, ∞], [2]]       (sort_by) 
  #=>   [[8, 6, 2], [2, 6, 8], [4, 1, 4]] 
my_sort [[8, 6, 2], [5, 1, 1], [6, 8, 4]]
  #=>   [[2],       [5, 1, 1], [4]        (sort_by) 
  #=>   [[8, 6, 2], [6, 8, 4], [5, 1, 1]] 

For each example I've shown the arrays used by sort_by to produce the sort shown on the following line.

Upvotes: 2

Related Questions