Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 如何对数组进行排序,使某些文件扩展名排序到顶部?_Perl_Arrays - Fatal编程技术网

Perl 如何对数组进行排序,使某些文件扩展名排序到顶部?

Perl 如何对数组进行排序,使某些文件扩展名排序到顶部?,perl,arrays,Perl,Arrays,我有一个包含文件列表的数组。我想对它进行排序,这样它就可以在数组的开头有.txt文件,之后还有其他文件 这就是我现在正在做的,效果很好 @files = (grep(/\.txt$/,@files),grep(!/\.txt$/,@files)); 但是有更好的方法吗?排序将可选块作为第一个参数,不过在这种情况下,施瓦茨变换会更快 @files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, !

我有一个包含文件列表的数组。我想对它进行排序,这样它就可以在数组的开头有.txt文件,之后还有其他文件

这就是我现在正在做的,效果很好

@files = (grep(/\.txt$/,@files),grep(!/\.txt$/,@files));

但是有更好的方法吗?

排序将可选块作为第一个参数,不过在这种情况下,施瓦茨变换会更快

@files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, !/\.txt$/ ] } @files;
@files=map{$\->[0]}sort{$a->[1]$b->[1]}map{[$\u,!/\.txt$/]}文件;
您只需在每个s前面添加一个:

这里的技巧是对列表进行分区,然后对每个分区进行独立排序。根据您正在做的事情,这可能比尝试在一个排序操作中完成所有操作要好得多。相反,它可能并不总是更好

有多种其他方法可以完成这一任务,但它们并不是这么简单。:)

下面是我的MacBook Air和vanilla Perl 5.10.1的快速基准测试:

There are 600 files to sort
     brian:  3 wallclock secs @ 369.75/s (n=1161)
   control:  3 wallclock secs @ 1811.99/s (n=5744)
      leon:  4 wallclock secs @ 146.98/s (n=463)
   mobrule:  3 wallclock secs @ 101.57/s (n=324)
      sort:  4 wallclock secs @ 559.62/s (n=1746)
以下是脚本:

use Benchmark;

use vars qw(@files);

@files = qw(
    buster.pdf
    mimi.xls
    roscoe.doc
    buster.txt
    mimi.txt
    roscoe.txt
    ) x 100;


printf "There are %d files to sort\n", scalar @files;

sub leon {  
    my @sorted = 
        map { $_->[0] } 
        sort { $a->[1] <=> $b->[1] } 
        map { [ $_, !/\.txt$/ ] 
        } @files;
    }

sub brian {
     my @sorted =
       (
       sort( grep /\.txt\z/,   @files ),
       sort( grep ! /\.txt\z/, @files )
       );
    }

sub mobrule {
    my @sorted = 
        sort { ($b=~/\.txt\z/) <=> ($a=~/\.txt\z/)  ||  $a cmp $b } 
        @files;
    }

sub plain_sort {
    my @sorted = sort @files;
    }

sub control {
    my @sorted = @files;
    }

timethese( -3,
     {
     brian   => \&brian,
     leon    => \&leon,
     mobrule => \&mobrule,
     control => \&control,
     sort    => \&plain_sort,
     }
     );
使用基准;
使用vars qw(@files);
@文件=qw(
buster.pdf
mimi.xls
罗斯科博士
buster.txt
mimi.txt
roscoe.txt
)x100;
printf“有%d个文件要排序\n”,scalar@files;
次里昂{
我的@sorted=
映射{$\->[0]}
排序{$a->[1]$b->[1]}
映射{[$\,!/\.txt$/]
}@文件;
}
亚布莱恩{
我的@sorted=
(
排序(grep/\.txt\z/,@files),
排序(grep!/\.txt\z/,@files)
);
}
次级规则{
我的@sorted=
排序{($b=~/\.txt\z/)($a=~/\.txt\z/)| |$a cmp$b}
@档案;
}
亚平原排序{
我的@sorted=sort@文件;
}
子控制{
我的@sorted=@文件;
}
这些时间(-3,
{
布莱恩=>\&布莱恩,
leon=>\&leon,
mobrule=>\&mobrule,
控件=>\&控件,
排序=>\&普通\u排序,
}
);

@sorted=sort{$b=~/\.txt$/$a=~/\.txt$/\\124; a cmp$b}@文件
将把.txt文件放在第一位,否则按字典顺序(字母顺序)排序

@sorted=sort{$b=~/\.txt$/$a=~/\.txt$/}@文件
将先放置.txt文件,否则将保留原始顺序(
sort
自Perl 5.8以来是稳定的)

代码? 这不会产生令人讨厌的警告:

@files = map { $_->[0] } sort { @$b <=> @$a } map { [$_, /\.txt$/] } @files
@files=map{$\->[0]}排序{$$b@$a}映射{[$\,/\.txt$/]}@files

您询问了关于对多个文件扩展名执行此操作的后续评论。在这种情况下,我将构建Schwartzian变换。如果您是ST新手,我推荐Joseph Hall关于有效Perl编程的解释。虽然这本书很快就要出版了,但我们基本上还是保留了他的解释,所以这本书也一样好。谷歌图书(GoogleBooks)第一版似乎只显示每页一英寸的内容,所以你在那里运气不好

在这个答案中,我使用加权函数来决定哪些扩展应该移到顶部。如果一个扩展没有明确的权重,我就按词法进行排序。您可以通过以下方式获得您想要的订单:

@files = qw(
    buster.pdf
    mimi.xls
    roscoe.doc
    buster.txt
    mimi.txt
    roscoe.txt
    buster.rpm
    mimi.rpm
    );

my %weights = qw(
    txt 10
    rpm  9
    );

my @sorted = 
    map { $_->{name} }
    sort { 
        $b->{weight} <=> $a->{weight}
         ||
        $a->{ext}    cmp $b->{ext}
         ||
        $a cmp $b
        }
    map {
        my( $ext ) = /\.([^.]+)\z/;
            { # anonymous hash constructor
            name => $_,
            ext => $ext,
            weight => $weights{$ext} || 0,
            }
        }
    @files;

$" = "\n";
print "@sorted\n";
@files=qw(
buster.pdf
mimi.xls
罗斯科博士
buster.txt
mimi.txt
roscoe.txt
buster.rpm
mimi.rpm
);
我的重量百分比=qw(
txt 10
转速9
);
我的@sorted=
映射{$\->{name}
排序{
$b->{weight}$a->{weight}
||
$a->{ext}cmp$b->{ext}
||
$a$b
}
地图{
我的($ext)=/\([^.]+)\z/;
{#匿名哈希构造函数
名称=>$\,
ext=>$ext,
权重=>$weights{$ext}| | 0,
}
}
@档案;
$“=”\n”;
打印“@sorted\n”;

为了有效地处理多个扩展,您可以通过一次对数组进行分区来修改brian d foy的排序
grep
s,然后对每个分区进行独立排序

use strict;
use warnings;

use List::MoreUtils qw(part);

my @files = qw(
    bar        Bar.pm       bar.txt
    bar.jpeg   foo          foo.pm
    foo.jpeg   zebra.txt    zebra.pm
    foo.bat    foo.c        foo.pl
    Foo.pm     foo.png      foo.tt
    orange     apple        zebra.stripe
);


my @parts = part { get_extension_priority($_) } @files;

my @sorted = map { sort( @{ $_ || [] } ) } @parts; 

print map "$_\n", @sorted;

BEGIN {

    # Set extension priority order
    my @priority = qw( stripe txt nomatch pl jpeg  );

    # make a hash to look up priority by extension
    my %p = map { $priority[$_], $_ } 0..$#priority;

    sub get_extension_priority {
        my $file = shift;

        return scalar @priority 
            unless /[.](\w*)$/;

        return scalar @priority 
            unless exists $p{$1};

        return $p{$1};
    }
}

在我的测试中,我发现Schwartzian变换有点慢(但只有一点).在我的回答中,我必须对数组进行两次遍历,但在你的示例中,你也是。你也必须进行引用。我第一次听说Schwartzian变换。它确实很有趣。假设我先要txt文件,然后是rpm,然后是其他文件。上面的代码需要如何更改?我不确定我是否需要更改了解它到底在做什么。@rarbox:看看所有这些,我认为这可能是最干净和最明显的。根据他关于想要排序更多文件扩展名的后续评论,这可能不是正确的答案。不,我不是在玩代码高尔夫。我在用Net::FTPSSL编写一个FTP客户端,遇到了一个我需要的情况ded文件以特定的顺序下载,我想知道是否有比我现在做的更好的排序方法。感谢您的回答。我几乎可以肯定@$b应该是错误的,但我不能让这个示例不起作用。在我看来,@$b应该被强制为一个数字,而不是比较数组中的某些内容,但我想这不会发生ing.Why它能工作?@brian d foy-如果/\.txt$/匹配,它将给出1,对数组的引用结果将包含类似['foo.txt',1]的内容;如果不匹配,则/\.txt$/将生成空列表,而空列表又会给出对类似['foo.bin'的数组的引用。正如您所看到的,具有匹配结果的数组将包含2个元素,否则为-1个元素。而且,是的,您是对的,在sort的块中,它被强制为数组中的许多元素。啊,很棘手。非常好。但是,我不会将其列为好的样式。:@brian d foy-是的,我不会将其投入生产。非常好!每次我看到part()虽然,我希望他刚才把它命名为partition():)这是O(n),而下面的排序是O(n log n)。如果你想要一个分区而不是一个排序,那么它是一个更好的选择。如果你想要排序,尽管,在一个操作中完成这一切。
@files = map { $_->[0] } sort { @$b <=> @$a } map { [$_, /\.txt$/] } @files
@files = qw(
    buster.pdf
    mimi.xls
    roscoe.doc
    buster.txt
    mimi.txt
    roscoe.txt
    buster.rpm
    mimi.rpm
    );

my %weights = qw(
    txt 10
    rpm  9
    );

my @sorted = 
    map { $_->{name} }
    sort { 
        $b->{weight} <=> $a->{weight}
         ||
        $a->{ext}    cmp $b->{ext}
         ||
        $a cmp $b
        }
    map {
        my( $ext ) = /\.([^.]+)\z/;
            { # anonymous hash constructor
            name => $_,
            ext => $ext,
            weight => $weights{$ext} || 0,
            }
        }
    @files;

$" = "\n";
print "@sorted\n";
use strict;
use warnings;

use List::MoreUtils qw(part);

my @files = qw(
    bar        Bar.pm       bar.txt
    bar.jpeg   foo          foo.pm
    foo.jpeg   zebra.txt    zebra.pm
    foo.bat    foo.c        foo.pl
    Foo.pm     foo.png      foo.tt
    orange     apple        zebra.stripe
);


my @parts = part { get_extension_priority($_) } @files;

my @sorted = map { sort( @{ $_ || [] } ) } @parts; 

print map "$_\n", @sorted;

BEGIN {

    # Set extension priority order
    my @priority = qw( stripe txt nomatch pl jpeg  );

    # make a hash to look up priority by extension
    my %p = map { $priority[$_], $_ } 0..$#priority;

    sub get_extension_priority {
        my $file = shift;

        return scalar @priority 
            unless /[.](\w*)$/;

        return scalar @priority 
            unless exists $p{$1};

        return $p{$1};
    }
}