0

I have an array of hashes:

array = [
    {
        id: 1,
        name: "A",
        points: 20,
        victories: 4,
        goals: 5,
    },
    {
        id: 1,
        name: "B",
        points: 20,
        victories: 4,
        goals: 8,
    },
    {
        id: 1,
        name: "C",
        points: 21,
        victories: 5,
        goals: 8,
    }
]

To sort them using two keys I do:

array = array.group_by do |key| 
[key[:points], key[:goals]] 
end.sort_by(&:first).map(&:last)

But in my program, the sort criterias are stored in a database and I can get them and store in a array for example: ["goals","victories"] or ["name","goals"].

How can I sort the array using dinamic keys?

I tried many ways with no success like this:

criterias_block = []
criterias.each do |criteria|
    criterias_block << "key[:#{criteria}]"
end

array = array.group_by do |key| 
    criterias_block 
end.sort_by(&:first).map(&:last)

3 Answers 3

5

Array#sort can do this

criteria = [:points, :goals]
array.sort_by { |entry|
  criteria.map { |c| entry[c] }
}

#=> [{:id=>1, :name=>"A", :points=>20, :victories=>4, :goals=>5},
#    {:id=>1, :name=>"B", :points=>20, :victories=>4, :goals=>8},
#    {:id=>1, :name=>"C", :points=>21, :victories=>5, :goals=>8}]

This works because if you sort an array [[1,2], [1,1], [2,3]], it sorts by the first elements, using any next elements to break ties

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

Comments

1

You can use values_at:

criteria = ["goals", "victories"]
criteria = criteria.map(&:to_sym)
array = array.group_by do |key| 
    key.values_at(*criteria)
end.sort_by(&:first).map(&:last)

# => [[{:id=>1, :name=>"A", :points=>20, :victories=>4, :goals=>5}, 
#      {:id=>1, :name=>"B", :points=>20, :victories=>4, :goals=>8}, 
#      {:id=>1, :name=>"C", :points=>21, :victories=>5, :goals=>8}]]

values_at returns an array of all the keys requested:

array[0].values_at(*criteria)
# => [4, 5]

Comments

1

I suggest doing it like this.

Code

def sort_it(array,*keys)
  array.map { |h| [h.values_at(*keys), h] }.sort_by(&:first).map(&:last)
end  

Examples

For array as given by you:

sort_it(array, :goals, :victories)
  #=> [{:id=>1, :name=>"A", :points=>20, :victories=>4, :goals=>5},
  #    {:id=>1, :name=>"B", :points=>20, :victories=>4, :goals=>8}, 
  #    {:id=>1, :name=>"C", :points=>21, :victories=>5, :goals=>8}]
sort_it(array, :name, :goals)
  #=> [{:id=>1, :name=>"A", :points=>20, :victories=>4, :goals=>5},
  #    {:id=>1, :name=>"B", :points=>20, :victories=>4, :goals=>8},
  #    {:id=>1, :name=>"C", :points=>21, :victories=>5, :goals=>8}]

For the first of these examples, you could of course write:

sort_it(array, *["goals", "victories"].map(&:to_sym))

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.