2016-04-02 89 views
3

我需要对数字进行排序,我无法按照自己想要的方式工作。Perl自然排序数字

示例输入:

15.12 
16.1 
15.2 
15.1 

预期输出:

15.1 
15.2 
15.12 
16.1 

我试图正常排序,并且还Sort::Naturally此。既不能给我预期的输出。

我也知道我可以像下面这样按照我想要的方式进行排序。

my @sorted = 
map sprintf('%vd', $_), 
sort 
map join('', map chr, split /\./), 
@data; 

我想知道是否有一些预先存在的模块,但我可以使用。

在此先感谢。

回答

3

它看起来像你想的版本号进行排序,其中每个组件是独立分类。 Sort ::自然不会工作,因为它忽略了非字母数字字符,但还有其他几个模块可以执行此操作。

Sort::Versions分割上周期或连字符的输入和排序每组任一字母或数字,这取决于非数字字符是否存在:

use strict; 
use warnings 'all'; 
use 5.010; 

use Sort::Versions; 

my @versions = (
    15.12, 
    16.1, 
    15.2, 
    15.1 
); 

say for sort { versioncmp($a, $b) } @versions; 

输出:

15.1 
15.2 
15.12 
16.1 

排序::版本期望输入匹配某些常见的版本字符串格式;如果您需要对不同的格式进行排序,请检查文档中的规则以确保它适用于您。


Sort::Key::Natural是更加灵活,因为它分裂的所有单词边界,不只是时间和连字符,但在这种情况下,它的工作原理是相同的:

use strict; 
use warnings 'all'; 
use 5.010; 

use Sort::Key::Natural qw(natsort); 

my @versions = (
    15.12, 
    16.1, 
    15.2, 
    15.1 
); 

say for natsort @versions; 

(输出是一样的排序: :Versions)

Sort :: Key :: Natural有一些很好的附加功能,比如就地排序和自定义排序顺序的能力。在我的基准测试中,它也比Sort :: Versions快得多,尽管如果你对大型数组进行排序,这只会影响你的工作。

+0

它们看起来像标准的浮点数字给我。假设它们是版本字符串是一个巨大的飞跃 – Borodin

+0

@Borodin看看预期的输出。他们想在15.12之前分类15.2。 – ThisSuitIsBlackNot

+0

你说得对。这很微妙。好的电话 – Borodin

3

您需要将数字与特殊$a$b变量进行比较(<=>)。请注意,您可以通过用cmp替换<=>来完成对字符串的操作。

use warnings; 
use strict; 

my @nums = qw(15.1 16.1 15.12); 

@nums = sort {$a <=> $b} @nums; 

print "$_\n" for @nums; 

__END__ 
15.1 
15.12 
16.1 
6

如果我的理解是正确的,要通过整数值的数字第一排序,然后再考虑小数部分为整数本身,因此.12.2更大就像你的榜样(12> 2)。

我觉得最自明的方法是使用自定义排序,分裂他们之后,你说:

@sorted = sort { 
    my ($a1, $a2) = split /\./, $a; 
    my ($b1, $b2) = split /\./, $b; 
    $a1 <=> $b1 or $a2 <=> $b2 
} @numbers;