0

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.

4
  • 3
    It is not because of the ternary operators or the if/elsif. Your algorithm is flawed. The a.odd? test passes and the block returns 1 for all elements. sort_by correctly concludes the array is already sorted. Commented Jan 23, 2019 at 21:22
  • @axiac Ouch. So it is! :facepalm: Thank you. I knew there was a reason I didn't want to post this. Commented Jan 23, 2019 at 21:31
  • 1
    "And I want to sort it by odd numbers..." is not clear, since you are sorting arrays, not numbers. When you give an example it's essential that you show the desired return value, which you have not done (and it's not obvious), but I think you would need a few examples and the desired result for each ito make the question clear. For exampel, suppose ary = [3, 6, 7], [8, 1, 9], [6, 8, 2]]. Are we to compare [3, ∞, 7], [∞, 1, 9], [2]] ( being Float:INFINITY) or [3, 7], [1, 9], [2]] or something else? Commented Jan 24, 2019 at 0:22
  • There is small type I guess in second code line as b:odd?, please check. Commented Jan 24, 2019 at 5:30

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Indeed! I do not know whether this is what OP intend to do but it is surely something that OP asked. Nice implementation done at edit!
Thanks for this one-liner. As I'm sure is entirely not to anyone's surprise, I'm very new to Ruby. I'm not new to explaining problems, though, and I did a bad job here. I sure appreciate everyone's help, and next time I have a question I'll ask it more carefully.
2

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.

1 Comment

Thanks for your help. Next time I ask a question I'll be more careful with it.

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.