【问题标题】:why does sort with uniq not work together为什么排序与 uniq 不能一起工作
【发布时间】:2013-11-27 19:00:13
【问题描述】:

我有以下脚本:

use strict;
use List::MoreUtils qw/uniq/;
use Data::Dumper;

my @x = (3,2);
my @y = (4,3);

print "unique results \n";
print Dumper([uniq(@x,@y)]);

print "sorted unique results\n";
print Dumper([sort uniq(@x,@y)]);

输出是

unique results 
$VAR1 = [
          3,
          2,
          4
        ];
sorted unique results
$VAR1 = [
          2,
          3,
          3,
          4
        ];

所以看起来 sort 不适用于 uniq。 我不明白为什么。

我用 -MO=Deparse 运行了 perl 脚本并得到了

use List::MoreUtils ('uniq');
use Data::Dumper;
use strict 'refs';
my(@x) = (3, 2);
my(@y) = (4, 3);
print "unique results \n";
print Dumper([uniq(@x, @y)]);
print "sorted unique results\n";
print Dumper([(sort uniq @x, @y)]);

我的解释是 perl 决定从 uniq(@x,@y) 中删除括号并使用 uniq 作为排序函数。

为什么 perl 决定这样做?

我怎样才能避免这些和类似的陷阱?

谢谢, 大卫

【问题讨论】:

    标签: perl


    【解决方案1】:

    sort builtin 接受一个子例程名称或块作为第一个参数,该参数传递两个项目。然后它必须返回一个确定项目之间顺序的数字。这些 sn-ps 都是一样的:

    use feature 'say';
    my @letters = qw/a c a d b/;
    
    say "== 1 ==";
    say for sort @letters;
    
    say "== 2 ==";
    say for sort { $a cmp $b } @letters;
    
    say "== 3 ==";
    sub func1 { $a cmp $b }
    say for sort func1 @letters;
    
    say "== 4 ==";
    sub func2 ($$) { $_[0] cmp $_[1] }  # special case for $$ prototype
    say for sort func2 @letters;
    

    注意函数名和列表之间没有逗号,注意 Perl 中的括号主要用于确定优先级——sort func1 @letterssort func1 (@letters) 是相同的,两者都不执行 func1(@letters) .

    要消除歧义,请在函数名称前添加 +

    sort +uniq @letters;
    

    为避免此类意外行为,最好的解决方案是在您不确定某个内置函数的行为方式时阅读文档 - 不幸的是,许多都有一些特殊的解析规则。

    【讨论】:

    • 我 100% 不明白为什么它不事先执行 uniq 然后使用排序列表,但我认为它更喜欢排序 SUBNAME LIST 形式。 + 号是​​什么意思?
    • @DavidMichaelGang 是的,问题是您的代码被解析为sort SUBNAME LIST。一元 + 禁止这种解释并强制“正常”调用 uniq。重要的是要记住sort 不是一个子程序——它是一个关键字,就像foreachgrep
    • DWIM 在这里失败,因为人们会期望与 sort grepsort map 相同的行为
    • 但是 mapgrep 是内置的,因此消歧启发式知道它们的作用,并且您不太可能尝试将它们用作自定义排序子。
    • @Сухой27、grepmap 是运算符,不是有效的子名称。
    【解决方案2】:

    你可以在 uniq 函数周围加上括号:

    print Dumper([sort (uniq(@x,@y))]);
    

    输出:

    $VAR1 = [
              2,
              3,
              4
            ];
    

    【讨论】:

    • 是的。这本可以解决它,但我的问题是为什么 perl 会这样工作。
    • 就是这样。某些 Perl 语法是模棱两可的,perl 需要猜测你的意图。它并不总是猜对的。
    • 这里没有歧义或猜测。更具体的语法 (sort SUBNAME LIST) 优先于不太具体的语法 (sort LIST)。
    猜你喜欢
    • 2010-10-28
    • 2021-04-29
    • 2015-03-16
    • 1970-01-01
    • 2021-08-18
    • 2021-07-19
    • 2021-03-27
    • 2021-05-08
    • 2021-12-06
    相关资源
    最近更新 更多