我有一个数组,每行中有许多字段,间距不同,如:
INDDUMMY drawing2 139 30 1 0 0 0 0 0
RMDUMMY drawing2 69 2 1 0 0 0 0 0
PIMP drawing 7 0 1444 718 437 0 0 0
我正在尝试按第3个字段中的数字对此数组进行排序,因此所需的输出应为:
PIMP drawing 7 0 1444 718 437 0 0 0
RMDUMMY drawing2 69 2 1 0 0 0 0 0
INDDUMMY drawing2 139 30 1 0 0 0 0 0
我尝试在排序函数中使用正则表达式进行拆分,如:
@sortedListOfLayers = sort {
split(m/\w+\s+(\d+)\s/gm,$a)
cmp
split(m/\w+\s+(\d+)\s/gm,$b)
}@listOfLayers;
但它无法正常工作。我怎么做那种排序?
答案 0 :(得分:1)
您需要进一步扩展排序功能。我也不确定split
是否按照您的想法运作。拆分基于分隔符将文本转换为数组。
我认为你的问题是你的正则表达式 - 感谢gm
标志 - 与你认为它匹配的东西不匹配。我可能会略微区别对待它:
#!/usr/bin/perl
use strict;
use warnings;
my @array = <DATA>;
sub sort_third_num {
my $a1 = (split ( ' ', $a ) )[2];
my $b1 = (split ( ' ', $b )) [2];
return $a1 <=> $b1;
}
print sort sort_third_num @array;
__DATA__
NDDUMMY drawing2 139 30 1 0 0 0 0 0
RMDUMMY drawing2 69 2 1 0 0 0 0 0
PIMP drawing 7 0 1444 718 437 0 0 0
例如,这就是诀窍。
如果您打算采用正则表达式方法:
sub sort_third_num {
my ($a1) = $a =~ m/\s(\d+)/;
my ($b1) = $b =~ m/\s(\d+)/;
return $a1 <=> $b1;
}
不全局匹配意味着只返回第一个元素。并且只返回'whitespace-digits'的第一个匹配项。我们也用数字比较,而不是字符串。
答案 1 :(得分:0)
如果要对列表进行排序并且sort
块中使用的操作很昂贵,常用的Perl惯用法是Schwartzian Transform:您将操作应用于每个列表元素并存储结果与原始元素一起排序,然后映射回原始格式。
经典教科书示例是使用昂贵的-s
文件测试按大小对目录中的文件进行排序。一种天真的方法是
my @sorted = sort { -s $a <=> -s $b } @unsorted;
每次比较操作必须执行两次-s
。
使用Schwartzian变换,我们将文件名映射到数组引用列表中,每个引用都引用一个包含list元素及其大小的数组(每个文件只需确定一次),然后按文件大小排序,最后将数组引用映射回文件名。这一切都只需一步完成:
my @sorted =
map $_->[0], # 3. map to file name
sort { a$->[1] <=> b$->[1] } # 2. sort by size
map [ $_, -s $_ ], # 1. evaluate size once for each file
@unsorted;
在您的情况下,问题是提取每个数组元素的第三个字段是多么昂贵。如有疑问,请measure比较不同的方法。对于几十个文件,文件大小示例中的加速比率大约为10倍!
适用于您的问题的Schwartzian变换看起来像这样:
my @sorted =
map $_->[0], # 3. Map to original array
sort { $a->[1] <=> $b->[1] } # 2. Sort by third column
map [ $_, ( split( ' ', $_ ) )[2] ], # 1. Use Sobrique's idea
@array;
如果使用的操作非常昂贵,以至于您希望避免每个值执行多次,以防您拥有相同的数组元素,则可以按this question中所述缓存结果;这被称为Orcish Maneuver。