阵列在Ruby中的一个阵列的哈希值,是通过有得分下降到阵列的这个哈希排序简短而亲切的方式:排序由红宝石
scored = {:id=>[1, 2, 3], :score=>[8.3, 5, 10]}
所以它看起来是这样的?:
scored = {:id=>[3, 1, 2], :score=>[10, 8.3, 5]}
我找不到一个例子,我可以在这样的散列内排序数组?我可以用一些令人讨厌的代码做到这一点,但我觉得应该有一个或两个班轮呢?
阵列在Ruby中的一个阵列的哈希值,是通过有得分下降到阵列的这个哈希排序简短而亲切的方式:排序由红宝石
scored = {:id=>[1, 2, 3], :score=>[8.3, 5, 10]}
所以它看起来是这样的?:
scored = {:id=>[3, 1, 2], :score=>[10, 8.3, 5]}
我找不到一个例子,我可以在这样的散列内排序数组?我可以用一些令人讨厌的代码做到这一点,但我觉得应该有一个或两个班轮呢?
你可以使用sort_by
scored = {:id=>[1, 2, 3], :score=>[8.3, 5, 10]}
scored.tap do |s|
s[:id] = s[:id].sort_by.with_index{ |a, i| -s[:score][i] }
s[:score] = s[:score].sort_by{ |a| -a }
end
#=> {:id=>[3, 1, 2], :score=>[10, 8.3, 5]}
以下是一种可能的解决方案。它有一个中间步骤,它利用scores
对象的压缩版本,但会产生正确的输出:
s = scored.values.inject(&:zip).sort_by(&:last).reverse
#=> [[3, 10], [1, 8.3], [2, 5]]
result = { id: s.map(&:first), score: s.map(&:last) }
#=> { :id => [3, 1, 2], :score => [10, 8.3, 5] }
order = scored[:score].each_with_index.sort_by(&:first).map(&:last).reverse
#=> [2,0,1]
scored.update(scored) { |_,a| a.values_at *order }
#=> {:id=>[3, 1, 2], :score=>[10, 8.3, 5]}
如果scored
是不被突变,用merge
代替update
。
几点:
order
很容易让读者了解发生了什么事情。<=>
的任何类)。arr
的另一种方法是使用Enumerable#max_by:arr.max_by(arr.size).to_a
。第一行可以替换为:
arr = scored[:score]
order = arr.each_index.sort_by { |i| arr[i] }.reverse
#=> [2,0,1]
我喜欢这个。特别是与命令的诡计。 – fl00r
去与这一个,因为我觉得这是稍微沟通。谢谢你。 – joshweir
同意可读性。在所有情况下进行两次'sort_by'调用的开销都可以忽略不计,并且也不需要分配额外的数组,如我的答案。唯一的(高度理论上的)并发问题是,如果你在排序调用之间改变了一个分数(当然这绝不会发生真实生活),那么你就被搞砸了。 :-)这可能是最好的答案。 – Drenmi
@Drenmi,我不同意。当我们可以分类一次时,我们不应该排序两次。如果值数组足够大,那么一次排序的方法将显着提高效率。而且,排序两次,即imo会对可读性产生不利影响。对不起,fl00r,但我不认为这个答案符合你通常的高标准。 –