Ruby Array按2种不同方式排序

And*_*ton 5 ruby arrays sorting

我有一个对象数组,我试图按多个标准排序.大多数比较只是<=>在他们的哈希上进行,所以使用sort_by非常快,但其中一个更复杂.

这个阵列是足球队的,目前它的排序方式如下:

teams.sort_by { |item| [item.points, item.goal_dif, item.goals] }
Run Code Online (Sandbox Code Playgroud)

但是,如果最后2支球队在这3个领域拥有相同的值,我希望决胜局是我所做的功能a_beat_b(teamA, teamB).

我尝试使用Array.sort,但sort_by与前几个相比,它非常慢...我的实现是这样的:

teams.sort ( |a,b| [a.points, a.goals_dif, a.goals] <=> [b.points, b.goals_dif, b.goals])
与sort_by相比,它非常慢.points,goals_dif和目标的函数需要一些简单的查询,但如果它必须做数百个就会陷入困境.

我不擅长Ruby,所以不确定把我a_beats_b放在哪里.(如果A击败,则返回1,0或-1,对B进行抽取或丢失,具有代表性)

Ste*_*fan 4

\n

我尝试使用,但与前几个Array.sort相比,它的速度非常慢sort_by

\n
\n\n

这是因为sort多次调用给定的块。这是一个示例,展示了幕后发生的事情:(排序"apple""pear"并按"fig"长度)

\n\n
def length(str)\n  puts "calculating #{str.inspect}.length"\n  str.length\nend\n\narray = %w{apple pear fig}\narray.sort { |a, b| length(a) <=> length(b) }\n#=> ["fig", "pear", "apple"]\n
Run Code Online (Sandbox Code Playgroud)\n\n

我们方法的输出length

\n\n
calculating "apple".length\ncalculating "pear".length\ncalculating "apple".length\ncalculating "fig".length\ncalculating "pear".length\ncalculating "fig".length\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如您所看到的,length在排序过程中被多次调用。想象一下这些是数据库查询。

\n\n

sort_by另一方面,为每个元素调用一次块,构建内部映射:

\n\n
array.sort_by { |a| length(a) }\n#=> ["fig", "pear", "apple"]\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:

\n\n
calculating "apple".length\ncalculating "pear".length\ncalculating "fig".length\n
Run Code Online (Sandbox Code Playgroud)\n\n

对于昂贵的操作(如数据库查询),这要快得多。但它也不太灵活\xe2\x80\x93,你无法动态比较a等等b

\n\n

但是,您可以存储(昂贵的)操作的结果,例如通过使用哈希:(这称为memoization

\n\n
hash = Hash.new { |h, k| h[k] = length(k) }\n
Run Code Online (Sandbox Code Playgroud)\n\n

并使用其中的哈希值sort

\n\n
array.sort { |a, b| hash[a] <=> hash[b] }\n# calculating "apple".length\n# calculating "pear".length\n# calculating "fig".length\n#=> ["fig", "pear", "apple"]\n
Run Code Online (Sandbox Code Playgroud)\n\n

排序后,我们的哈希看起来像这样:

\n\n
hash #=> {"apple"=>5, "pear"=>4, "fig"=>3}\n
Run Code Online (Sandbox Code Playgroud)\n\n

应用于您的代码,类似这样的事情应该有效:

\n\n
hash = Hash.new { |h, k| h[k] = [k.points, k.goal_dif, k.goals] }\nteams.sort { |a, b| hash[a] == hash[b] ? a_beats_b(a, b) : hash[a] <=> hash[b] }\n
Run Code Online (Sandbox Code Playgroud)\n