Perl 6 单行打印文件的唯一行

Perl 6 one-liner to print unique lines of a file

我发现这个非常有用的单行代码,它可以工作,但我不明白它是如何设法在文件的行中循环两次的。

perl6 -ne 'state %l; .say if ++%l{$_} == 1' input-file.txt

只有一个循环
它收集所有行作为 %l 中的键,值是它看到它的次数。
如果这是第一次 (… == 1) 它遇到了打印当前行的副本。

它的工作原理与:

基本相同
my %l;

for $*ARGFILES.lines() {  # this is basically what `-n` does

  ++%l{ $_ };             # update the count

  .say if %l{ $_ } == 1;  # print it if this is the first time it was seen

}

我认为使用 … if ++$… == 1 而不是 … unless $…++ 的原因是 &prefix:«++» is slightly more performant than &postfix:«++»


另一种可能更有效(取决于 .unique 的实现)的编写方式是:

perl6 -e '.put for $*ARGFILES.lines.unique' input-file.txt

让我们来解压一下。 -n 选项在代码周围添加了一个 for lines() { ... } 循环,所以我们有

for lines() { 
    state %l;
    .say if ++%l{$_} == 1
}

为什么是 state 变量?没有简单的方法可以在那一行的隐式循环的外部范围内声明变量。否则你会写成

my %l;
for lines() { 
    .say if ++%l{$_} == 1
}

%l 跟踪一行(存储在 $_ 中)被看到的次数。它使用 autovification,所以第一次看到一行时,++ 运算符会自动将其添加到散列中。

.say 是 shorthand 对于 $_.say

也许是一个更具可读性的 Raku 单行代码以摆脱重复行:

raku -e 'lines.unique.join("\n").put;' input-file.txt

简而言之,-n-p 命令行标志均未设置:使用 lines 读取输入。 unique 命令用于使行唯一。由于 lines auto-chomps 尾随换行符,输出被 joinjoin("\n") 一起返回到 return linewise 输出。

或者:

raku -e '.unique.join("\n").put given lines;' input-file.txt

上面使用了 given 外用剂。根据文档:"given 可以跟在语句后面以在其后的语句中设置主题。" 同样,-n-p 设置命令行标志:使用 lines.

读取输入

https://docs.raku.org/syntax/given