假设数据包含在 string$string
中,此解决方案将起作用:
my %seen; # just needed to remove duplicates
my $deduped_string =
join "\n", # 6. join the lines to a single string
map { join(" ", @$_) } # 5. join the fields of each line to a string
sort { $a->[-1] <=> $b->[-1] } # 4. sort arrayrefs by last field, numerically
map { [split] } # 3. split line into fields, store in anon arrayref
grep { not $seen{$_}++ } # 2. dedupe the lines
split /\n/, $string; # 1. split string into lines
这个庞大的表达式从下到上(或从右到左)执行。它由多个可组合的变压器和滤波器组成:
map {BLOCK} LIST
将块中的代码应用于列表的每个值。它按元素转换列表。
grep {BLOCK} LIST
从块返回 true 的列表中选择那些元素。因此,它过滤列表并仅输出满足特定条件的元素。
sort {BLOCK} LIST
度假村名单。$a
如果小于,则该块必须返回 -1 ,如果大于,则返回 1 $b
,或者如果相等则返回零。运算符以这种方式对<=>
标量进行数值比较。如果省略排序函数,则使用字符串比较。
join STRING, LIST
将列表的元素与中间的字符串连接起来。
split REGEX, STRING
将字符串分成几块。正则表达式匹配分隔符(通常不返回)。split
并且join
可以被认为是逆运算。如果字符串被省略,$_
则使用。当正则表达式被省略时,它的工作方式类似于split /\s+/, $_
,即在每个空白字符处拆分。
该解决方案的核心是Schwartzian Transform,这是一种技术/习语,可以通过计算成本高昂的键进行廉价排序。在它的一般形式中,它是
my @sorted_data =
map { $_->[0] } # 3. map back to the orginal value
sort { $a->[1] <=> $b->[1] } # 2. sort by the special key
map { [$_, create_the_key($_)] } # 1. annotate each value with a key
@data;
在我的具体情况下,特殊键是每条记录的最后一列;为了从带注释的数据中获取原始数据(或等效形式),我将这些字段连接在一起。正如mpapec指出的那样,我也可以将原始线带入变换;这将保留线条的原始对齐方式。