【问题标题】:Sort numbers with the format x.x.x.x in perl在 perl 中使用 x.x.x.x 格式对数字进行排序
【发布时间】:2012-07-21 04:53:50
【问题描述】:

比如说数字的格式:

1.1.10
1.1.10.1
1.1.10.2
1.1.11
1.1.12
1.1.13
1.1.13.1
1.1.3
1.1.4

我正在寻找的输出是:

1.1.3
1.1.4
1.1.10
1.1.10.1
1.1.10.2
1.1.11
1.1.12
1.1.13
1.1.13.1

【问题讨论】:

  • 不是 6917314 的副本。iDev 的字符串不完全有 4 个部分,而且他没有说它们被限制为 255 个部分。
  • 快速破解:sort { eval $a cmp eval $b } @numbers
  • @Cupidvogel, 1.1.1.10v1.1.1.10 相同,字符串化为 chr(1).chr(1).chr(1).chr(10)。换句话说,eval "1.1.1.10" 是一种昂贵且冒险的方式来做pack "W*", split /\./, "1.1.1.10"。是的,您可以将我的解决方案中的包模板中的“C”更改为“W”。在 32 位 Perls 上最多可以处理 40 亿个数字,在 64 位机器上最多可以处理 2**64-1。
  • @Cupidvogel stackoverflow.com/a/7142844/725418 在 cmets 中,tchrist 详细阐述了这个特殊的“技巧”。基本上它就像 ikegami 所说的那样,它将准数字字符串转换为适当的字符串,之后我们可以“安全地”将它与 cmp 运算符一起使用。我将其命名为 quick hack,因为它可能不是解决这个特定问题的好方法。

标签: perl sorting


【解决方案1】:
use Sort::Key::Natural qw( natsort );
my @sorted = natsort @data;

或(无模块)

my @sorted =
   map $_->[0],
   sort { $a->[1] cmp $b->[1] }
   map [ $_, pack('C*', split /\./) ],
   @data;

或(无模块,速度更快,但需要一个数组而不是列表作为输入)

 my @sorted =
   map $data[unpack('N', $_)],
   sort
   map pack('NC*', $_, split /\./, $data[$_]),
   0..$#data;

pack 模板中,您可以将C 更改为nNC 允许最多 255 个数字。n 允许最多 65,535 个数字。 N 最多允许 40 亿个数字。

【讨论】:

  • 无法弄清楚排序在获取 pack(...) 数据时是如何工作的,在这种情况下,pack 只是从每个版本号中创建一个八位字节值...不是将每个数字与'cmp' 会做同样的事情吗?
  • @soulSurfer2010, "1.2.1" cmp "1.16.1" 失败,因为数字的宽度可变。使用pack C,使它们都具有相同的宽度。它归结为"\x01\x02\x01" cmp "\x01\x10\x01",由于添加了填充,它正确排序。
【解决方案2】:

尝试以下方法:

use Modern::Perl;
use Sort::Naturally  qw{nsort};

my @numbers = nsort(qw{1.1.10 1.1.10.1 1.1.10.2 1.1.11 1.1.12 1.1.13 1.1.13.1 1.1.3});
say for @numbers;

输出:

1.1.3
1.1.10
1.1.10.1
1.1.10.2
1.1.11
1.1.12
1.1.13
1.1.13.1

希望这会有所帮助!

【讨论】:

    【解决方案3】:

    这对你来说可能更容易理解:

    sub min { $_[0] <= $_[1] ? $_[0] : $_[1] }
    sub comp 
      {
      ($a1,$a2) = @_;
      @a1 = @{$a1};
      @a2 = @{$a2};
      for (0..min(scalar @a1,scalar @a2)) 
         {
         return 1 if $a1[$_] > $a2[$_];
         return -1 if $a2[$_] > $a1[$_];  #exit early if an inequality is found
         }
      return 0 if @a1 == @a2; #both array are equal, thus both numbers are equal
      return @a1 > @a2 ? 1 : -1; #arrays are equal upto a certain point, thus longer array is 'greater'
      }
    @sourcearray = ('1.1.10','1.1.10.1','1.1.10.2','1.1.11','1.1.12','1.1.13','1.1.13.1','1.1.3','1.1.4');
    @individual = map { [split /\./] } @sourcearray; #splits each number into arrays consisting of individual numbers
    @sorted = sort {comp($a,$b)} @individual; #sort algo decides which of these two arrays are 'greater'
    {
    local $" = ".";
    print "@{$sorted[$_]}\n" for 0..$#sorted;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-13
      • 1970-01-01
      • 1970-01-01
      • 2018-01-10
      相关资源
      最近更新 更多