Perl自然排序数字

3

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

示例输入:

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;

我想知道是否有一些现成的模块可以使用。

提前感谢。

4个回答

6

如果我理解正确,您想首先按整数值对数字进行排序,然后将小数部分视为整数本身,因此像您的示例中一样,.12 大于 .2(因为 12 > 2)。

我认为最易于理解的方法是使用自定义排序,在拆分它们后进行排序,就像您所说的那样:

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

4

看起来你正在尝试对版本号进行排序,其中每个组件是独立排序的。Sort::Naturally无法工作,因为它忽略非字母数字字符,但是还有其他几个模块可以做到这一点。

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::Versions期望输入与某些常见版本字符串格式匹配;如果您需要对不同于您所显示的格式进行排序,请检查文档中的规则以确保它适用于您。


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;

(输出与Sort::Versions相同)

Sort::Key::Natural具有一些不错的附加功能,例如能够就地排序和自定义排序顺序。在我的基准测试中,它比Sort::Versions快得多,尽管只有在对大型数组进行排序时才会有所影响。


它们对我来说看起来像标准的浮点数。假设它们是版本字符串是一个很大的飞跃。 - Borodin
@Borodin 看一下期望的输出。他们想要在15.12之前对15.2进行排序。 - ThisSuitIsBlackNot
是的,它们是版本号。谢谢您,您的方案确实有效。 - Stacky

1

您需要使用特殊变量$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

这似乎并没有回答问题,并且会丢失值“15.2”,这将显示为与问题中的需求不匹配。 - Richlv
@Richlv 很好的发现!我不知道我怎么会错过那个。 - stevieb

1

关于@stevieb提供的答案,数值"15.2"并没有被删除:它在原始数组中是缺失的。然而,运算符<=>cmp不能互换使用。它们分别用于比较数字和字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接