Ruby - 使用动态键排序

时间:2021-11-03 16:00:59

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?

如何使用dinamic键对数组进行排序?

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 个解决方案

#1


5  

Array#sort can do this

Array#sort可以做到这一点

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

这是有效的,因为如果你对数组[[1,2],[1,1],[2,3]]进行排序,它会按照第一个元素进行排序,使用任何下一个元素来断开关系

#2


1  

You can use values_at:

你可以使用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:

values_at返回所请求的所有键的数组:

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

#3


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))

#1


5  

Array#sort can do this

Array#sort可以做到这一点

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

这是有效的,因为如果你对数组[[1,2],[1,1],[2,3]]进行排序,它会按照第一个元素进行排序,使用任何下一个元素来断开关系

#2


1  

You can use values_at:

你可以使用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:

values_at返回所请求的所有键的数组:

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

#3


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))