How to sort an alphanumeric array in ruby

后端 未结 8 1882
没有蜡笔的小新
没有蜡笔的小新 2021-01-19 16:01

How I can sort array data alphanumerically in ruby?

Suppose my array is a = [test_0_1, test_0_2, test_0_3, test_0_4, test_0_5, test_0_6, test_0_7, test_0_8, te

8条回答
  •  长发绾君心
    2021-01-19 16:30

    Sort routines can have greatly varying processing times. Benchmarking variations of the sort can quickly home in on the fastest way to do things:

    #!/usr/bin/env ruby
    
    ary = %w[
        test_0_1  test_0_2   test_0_3 test_0_4 test_0_5  test_0_6  test_0_7
        test_0_8  test_0_9   test_1_0 test_1_1 test_1_2  test_1_3  test_1_4  test_1_5
        test_1_6  test_1_7   test_1_8 test_1_9 test_1_10 test_1_11 test_1_12 test_1_13
        test_1_14 test_1_121
    ]
    
    require 'ap'
    ap ary.sort_by { |v| a,b,c = v.split(/_+/); [a, b.to_i, c.to_i] }.reverse
    

    And its output:

    >> [
    >>     [ 0] "test_1_121",
    >>     [ 1] "test_1_14",
    >>     [ 2] "test_1_13",
    >>     [ 3] "test_1_12",
    >>     [ 4] "test_1_11",
    >>     [ 5] "test_1_10",
    >>     [ 6] "test_1_9",
    >>     [ 7] "test_1_8",
    >>     [ 8] "test_1_7",
    >>     [ 9] "test_1_6",
    >>     [10] "test_1_5",
    >>     [11] "test_1_4",
    >>     [12] "test_1_3",
    >>     [13] "test_1_2",
    >>     [14] "test_1_1",
    >>     [15] "test_1_0",
    >>     [16] "test_0_9",
    >>     [17] "test_0_8",
    >>     [18] "test_0_7",
    >>     [19] "test_0_6",
    >>     [20] "test_0_5",
    >>     [21] "test_0_4",
    >>     [22] "test_0_3",
    >>     [23] "test_0_2",
    >>     [24] "test_0_1"
    >> ]
    

    Testing the algorithms for speed shows:

    require 'benchmark'
    
    n = 50_000
    Benchmark.bm(8) do |x|
      x.report('sort1') { n.times { ary.sort { |a,b| b <=> a }         } }
      x.report('sort2') { n.times { ary.sort { |a,b| a <=> b }.reverse } }
      x.report('sort3') { n.times { ary.sort { |a,b|
                                      ap = a.split('_')
                                      a = ap[0] + "%05d" % ap[1] + "%05d" % ap[2]
                                      bp = b.split('_')
                                      b = bp[0] + "%05d" % bp[1] + "%05d" % bp[2]
                                      b <=> a
                                    } } }
    
      x.report('sort_by1') { n.times { ary.sort_by { |s| s                                               }         } }
      x.report('sort_by2') { n.times { ary.sort_by { |s| s                                               }.reverse } }
      x.report('sort_by3') { n.times { ary.sort_by { |s| s.scan(/\d+/).map{ |s| s.to_i }                 }.reverse } }
      x.report('sort_by4') { n.times { ary.sort_by { |v| a = v.split(/_+/); [a[0], a[1].to_i, a[2].to_i] }.reverse } }
      x.report('sort_by5') { n.times { ary.sort_by { |v| a,b,c = v.split(/_+/); [a, b.to_i, c.to_i]      }.reverse } }
    end
    
    
    >>               user     system      total        real
    >> sort1     0.900000   0.010000   0.910000 (  0.919115)
    >> sort2     0.880000   0.000000   0.880000 (  0.893920)
    >> sort3    43.840000   0.070000  43.910000 ( 45.970928)
    >> sort_by1  0.870000   0.010000   0.880000 (  1.077598)
    >> sort_by2  0.820000   0.000000   0.820000 (  0.858309)
    >> sort_by3  7.060000   0.020000   7.080000 (  7.623183)
    >> sort_by4  6.800000   0.000000   6.800000 (  6.827472)
    >> sort_by5  6.730000   0.000000   6.730000 (  6.762403)
    >> 
    

    Sort1 and sort2 and sort_by1 and sort_by2 help establish baselines for sort, sort_by and both of those with reverse.

    Sorts sort3 and sort_by3 are two other answers on this page. Sort_by4 and sort_by5 are two spins on how I'd do it, with sort_by5 being the fastest I came up with after a few minutes of tinkering.

    This shows how minor differences in the algorithm can make a difference in the final output. If there were more iterations, or larger arrays being sorted the differences would be more extreme.

提交回复
热议问题