1

If I have a method that adds two arrays of hashes together and then sorts them based on a specified order, is it possible to sort it again based on a second specified order?

If I my method looks something like:

def all_pets

     #set order by fur color
     order = ['Black', 'Orange', 'Golden', 'Mixed']

     all_pets = dogs + cats #two arrays being added together

     all_pets.sort_by {|r| order.index(r[:fur_color])}

end

My output currently looks like:

  [{:name=>"Kitty", :fur_color=>"Black"} #cat,
  {:name=>"Fido", :fur_color=>"Black"} #dog, 
  {:name=>"Whiskers", :fur_color=>"Black"} #cat, 
  {:name=>"Buttons", :fur_color=>"Orange"} #cat, 
  {:name=>"Mr.Cat", :fur_color=>"Golden"} #cat, 
  {:name=>"Sparky", :fur_color=>"Golden"} #dog,
  {:name=>"Max", :fur_color=>"Mixed"} #dog]

This is great so far, I have the animals sorted by fur color exactly how I want, is it possible to then sort so cats will always come after dogs?

The two arrays being added have the exact same attributes (name and fur color), so I'm not sure how to order them by fur color first, and animal type second.

Since both arrays have the same attributes, and no animal type attribute, would it be possible to do something that puts all hashes that came from the array cat to come after the hashes from array dog after they've been sorted by fur color?

So my goal output would be:

  [{:name=>"Fido", :fur_color=>"Black"} #dog,
   {:name=>"Kitty", :fur_color=>"Black"} #cat, 
  {:name=>"Whiskers", :fur_color=>"Black"} #cat, 
  {:name=>"Buttons", :fur_color=>"Orange"} #cat, 
  {:name=>"Sparky", :fur_color=>"Golden"} #dog,
  {:name=>"Mr.Cat", :fur_color=>"Golden"} #cat, 
  {:name=>"Max", :fur_color=>"Mixed"} #dog]

Thanks!

6
  • 1
    Which animals are cats (or dogs) ? Commented Jul 26, 2018 at 16:22
  • 1
    When you say you want cats to come before dogs, do you mean you want all all black dogs, then all orange dogs, then all golden dogs, then all mixed dogs, then all black cats, then all orange cats, then all golden cats, then all mixed cats? Commented Jul 26, 2018 at 16:23
  • @Piccolo Edited my post, hopefully its a bit more clear. Thanks! Commented Jul 26, 2018 at 16:36
  • Possible duplicate of How to sort an array of hashes in ruby Commented Jul 26, 2018 at 20:25
  • 1
    @jedi, the question you reference is concerned with sorting an array of hashes on a single key's value. Commented Jul 27, 2018 at 2:32

2 Answers 2

3

Just pass an array to sort_by:

all_pets.sort_by {|r| [order.index(r[:fur_color]), r[:name]] }

The above will sort by the color and by the name inside the same color.

all_pets.sort_by do |r|
  [
    order.index(r[:fur_color]),
    cats.map { |c| c[:name] }.include?(r[:name])
    # or cats.include?(r)
  ]
end

The latter will put cats after dogs.

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

7 Comments

@SergioTulentsev why not? I am into Erlang ideology nowadays, it explicitly says: fail fast!
When I read "put cats after dogs", my initial thought was "give me a research team and 5 years". But the solution is trivial, turns out. :)
@SergioTulentsev yeah, nested sorting is kinda easier than ML :)
Why would you use cats.map { |c| c[:name] }.include?(r[:name]) instead of cats.include?(r)? The latter seems cleaner and I can't imagine any performance benefit
@Piccolo for the sake of example. I explicitly mentioned cats.include?(r) variant in a comment 1 line below.
|
2

Here we can make use of the fact that, when used without a block, Enumerable#sort_by returns an enumerator.

COLOR_ORDER = ['Black', 'Orange', 'Golden', 'Mixed'].each_with_index.to_h
  #=> {"Black"=>0, "Orange"=>1, "Golden"=>2, "Mixed"=>3}

def sort_pets(pets)
  pets.sort_by.with_index { |pet, idx| [COLOR_ORDER[pet[:fur_color]], idx] }
end

dogs = [{ :name=>"Sparky",   :fur_color=>"Golden" },
        { :name=>"Max",      :fur_color=>"Mixed"  }, 
        { :name=>"Fido",     :fur_color=>"Black"  }]

cats = [{ :name=>"Kitty",    :fur_color=>"Black"  }, 
        { :name=>"Whiskers", :fur_color=>"Black"  }, 
        { :name=>"Buttons",  :fur_color=>"Orange" },
        { :name=>"Mr.Cat",   :fur_color=>"Golden" }]

sort_pets(dogs + cats)
  #=> [{:name=>"Fido",     :fur_color=>"Black "},
  #    {:name=>"Kitty",    :fur_color=>"Black" },
  #    {:name=>"Whiskers", :fur_color=>"Black" },
  #    {:name=>"Buttons",  :fur_color=>"Orange"},
  #    {:name=>"Sparky",   :fur_color=>"Golden"},
  #    {:name=>"Mr.Cat",   :fur_color=>"Golden"},
  #    {:name=>"Max",      :fur_color=>"Mixed" }]

Comments

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.