How do I order an array in ruby ​​when the order has four different conditions?

I'm not sure how I can reorder an array based on two booleans in Ruby. I would like to order my results in the following order:

* Note awkward ordering *
1) is_strong: true, requires_api_check: false
2) is_strong: true, requires_api_check: true
3) is_strong: false, requires_api_check: true 
4) is_strong: false, requires_api_check: false

      

And I wrote some pseudo code to get it back in the correct order, but it doesn't work. I realize I can only return -1,0, + 1, but I'm not sure how to handle this situation.

objects = [
            OpenStruct.new(is_strong: false, requires_api_check: false),
            OpenStruct.new(is_strong: false, requires_api_check: true),
            OpenStruct.new(is_strong: true, requires_api_check: false),
            OpenStruct.new(is_strong: true, requires_api_check: true),
        ]


      objects.sort do |res|
        if res.is_strong
          if !res.requires_api_check
            1
          else
            2
          end
        else
          if res.requires_api_check
            3
          else
            4
          end
        end
      end

      

+3


source to share


2 answers


Just use sort_by

which is available in arrays via Enumerable .

sort

gives two compare objects with a block and expects a value < 0

, 0

or > 0

. This allows you to define custom sorting rules between potentially unrelated objects.

sort_by

on the other hand, gives only one object to a block. Anything that is returned from the block is then used for comparison. If you return integers, your final array will be sorted by those raw Integer values.



So, given your "awkward" sorting rules, your code works great if you use sort_by

instead sort

, without having to express your rules in terms of spaceship rules .

In the example below, I have shortened your code a bit with ternary operators.

objects.sort_by do |res|
  if res.is_strong
    res.requires_api_check ? 2 : 1
  else
    res.requires_api_check ? 3 : 4
  end
end

      

+2


source


Since there doesn't seem to be any perceived logic, hardcoding AWKWARD_ORDERING is the way to go:



require "ostruct"

AWKWARD_ORDERING = [[true, false],[true,true],[false,true],[false, false]]

objects = [
            OpenStruct.new(is_strong: false, requires_api_check: false),
            OpenStruct.new(is_strong: false, requires_api_check: true),
            OpenStruct.new(is_strong: true, requires_api_check: false),
            OpenStruct.new(is_strong: true, requires_api_check: true),
        ]

p res =  objects.sort{|obj| AWKWARD_ORDERING.index([obj.is_strong, obj.requires_api_check])}

      

+2


source







All Articles