Ruby Sort_by 多个参数与 asc/desc 相反

duc*_*615 3 ruby sorting

尝试按多个参数排序,但在一个参数升序排序和另一个参数降序排序时遇到问题。

array = [20, 10, 40, 1200, 300]
Run Code Online (Sandbox Code Playgroud)

我需要首先按每个数字降序的位数对数组进行排序。

所以我们得到 [1200, 120, 40, 10, 20]

如果长度之间存在联系,我需要按值对它们进行升序排序

所以我们得到: [1200, 120, 10, 20, 40]

我正在尝试使 sort_by 为此工作,但我无法弄清楚如何对第一个参数进行降序排序和第二个参数升序排序。

def digit_sorter(ar) 
   ar.sort_by {|num| [num.to_s.length, num]}.reverse 
end
Run Code Online (Sandbox Code Playgroud)

我也试过 [ [num.to_s.length], [num].reverse ]

spi*_* 王建 5

# length desc, value asc
def digit_sorter(nums)
  nums.sort { |a, b| [b.to_s.length, a] <=> [a.to_s.length, b] }
end


# length asc, value desc
def digit_sorter(nums)
  nums.sort { |a, b| [a.to_s.length, b] <=> [b.to_s.length, a] }
end
Run Code Online (Sandbox Code Playgroud)

输入相同的数组[345, 23, 34, 1],输出分别为

# length desc, value asc
[345, 23, 34, 1]

# value desc, length asc
[1, 34, 23, 345]
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的通用解决方案,因为它不需要将对象排序为数字。 (2认同)

Tim*_*and 5

总是喜欢sort_bysort时,速度可能是一个问题,sort关键是计算昂贵。
对于升序,只需在此处按原样使用排序键a(数组元素的值)。对于降序,使用-key减号键),这里-a.to_s.length(数组元素的长度):

array = [20, 10, 40, 1200, 300]
puts array.sort_by { |a| [-a.to_s.length, a] }
Run Code Online (Sandbox Code Playgroud)

印刷:

1200
300
10
20
40
Run Code Online (Sandbox Code Playgroud)

哪个更快:sort_bysort

sort_by[是] 当键集很简单时相当昂贵。... 但是,请考虑比较密钥是一项重要操作的情况。一种更有效的技术是sortsort. Perl 用户经常在 Randal Schwartz 之后称这种方法为 Schwartzian 变换。......这正是sort_by 内部所做的。

(来自sort_by文档

也可以看看

Brandon Dimcheff:“Ruby 的排序与 sort_by”


基准sort_bysort:

对于 OP 描述的情况,sort_by比 略快sort,尽管两者都很快,因为数组很小(size = 5,见下文)。由于减少了对昂贵的密钥计算的需求,随着数组增长到更现实size=10, 100, 1000sort_by速度大约是原来的两倍sort。请注意,相对性能在很大程度上取决于数组大小以及sort计算键的成本,因此将其视为单个数据点,不要过度概括这些结果。

代码:

#!/usr/bin/env ruby

require 'benchmark' 

max_val = 2_000

[5, 10, 100, 1000].each do |size|
  puts "###"
  puts "array size=#{size}:"
  puts "###"
  Benchmark.bmbm do |x|
    Kernel.srand(1234)
    x.report("sort_by")    { 10000.times { (1..size).to_a.map { rand(max_val) } .sort_by { |a| [-a.to_s.length, a] }  } }
    Kernel.srand(1234)
    x.report("sort") { 10000.times { (1..size).to_a.map { rand(max_val) } .sort { |a, b| [b.to_s.length, a] <=> [a.to_s.length, b] } } } 
  end
end
Run Code Online (Sandbox Code Playgroud)

结果:

###
array size=5:
###
Rehearsal -------------------------------------------
sort_by   0.070000   0.000000   0.070000 (  0.062603)
sort      0.070000   0.000000   0.070000 (  0.074214)
---------------------------------- total: 0.140000sec

              user     system      total        real
sort_by   0.060000   0.000000   0.060000 (  0.061337)
sort      0.070000   0.000000   0.070000 (  0.070706)
###
array size=10:
###
Rehearsal -------------------------------------------
sort_by   0.110000   0.000000   0.110000 (  0.117958)
sort      0.190000   0.000000   0.190000 (  0.183992)
---------------------------------- total: 0.300000sec

              user     system      total        real
sort_by   0.110000   0.000000   0.110000 (  0.116410)
sort      0.180000   0.000000   0.180000 (  0.184045)
###
array size=100:
###
Rehearsal -------------------------------------------
sort_by   1.770000   0.010000   1.780000 (  1.776254)
sort      3.800000   0.000000   3.800000 (  3.797437)
---------------------------------- total: 5.580000sec

              user     system      total        real
sort_by   1.780000   0.000000   1.780000 (  1.783407)
sort      3.860000   0.000000   3.860000 (  3.865884)
###
array size=1000:
###
Rehearsal -------------------------------------------
sort_by  25.380000   0.010000  25.390000 ( 25.403899)
sort     60.290000   0.040000  60.330000 ( 60.374564)
--------------------------------- total: 85.720000sec

              user     system      total        real
sort_by  26.010000   0.060000  26.070000 ( 26.122175)
sort     60.990000   0.060000  61.050000 ( 61.134355)
Run Code Online (Sandbox Code Playgroud)