【问题标题】:Ruby Sort_by multiple parameters opposite asc/descRuby Sort_by 多个参数相反 asc/desc
【发布时间】:2020-08-25 04:41:54
【问题描述】:

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

array = [20, 10, 40, 1200, 300]

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

所以我们得到[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

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

【问题讨论】:

  • 提示:如何反转一个数字?你如何把一个数字变成它的反面?

标签: ruby sorting


【解决方案1】:
# 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

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

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

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

【讨论】:

  • 这是一个很好的通用解决方案,因为它不需要被排序的对象是数字。
【解决方案2】:

当速度可能成为问题并且 sort 密钥的计算成本很高时,总是更喜欢 sort_by 而不是 sort
对于升序,只需按原样使用排序键,此处为a(数组元素的值)。对于降序,使用-key键),这里是-a.to_s.length(数组元素的长度):

array = [20, 10, 40, 1200, 300]
puts array.sort_by { |a| [-a.to_s.length, a] }

打印:

1200
300
10
20
40

哪个更快:sort_bysort

sort_by [is] 当键集很简单时相当昂贵。 ... 但是,考虑比较密钥是不平凡的情况 手术。一种更有效的技术是缓存sort 键... 在sort 之前。 Perl 用户通常称这种方法为 Schwartzian 在 Randal Schwartz 之后转变。 ...这正是sort_by 在内部进行。

(来自sort_by docs

另见

Brandon Dimcheff: "Ruby's sort vs. sort_by"


基准测试sort_bysort

对于 OP 描述的情况,sort_bysort 稍快,尽管两者都很快,因为数组很小(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

结果:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 2015-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多