【问题标题】:Perl Sort ArrayPerl 排序数组
【发布时间】:2013-08-10 01:58:33
【问题描述】:

我想弄清楚如何在 Perl 中对文件名列表进行排序。

每个文件都是一个 PDF 文件,我使用 Perl 的 PDF::Reuse 将其合并为一个 pdf

每个 pdf 文件名都有两个唯一标识符。 1) 是帐户 ID & 2) 报告类型。

例子:

C1234.lfs.pdf

C1234 = 帐户 ID lfs = 报告类型。

每个帐户可以有多个需要按特定顺序排列的报告。

如何指定报告类型的顺序?我想使用一个配置文件,脚本将在其中查看在合并到 1 个 pdf 文件之前对每个帐户报告进行排序的顺序。 我想要的顺序是:

AcctId.lau.pdf AcctId.lsm.pdf AcctId.lad.pdf AcctId.lfs.pdf AcctId.lbe.pdf

@PDFS = (<*l*.pdf>);
@REVERSED_LIST = reverse(@PDFS);
prFile($OutPut);
for my $pdf (@REVERSED_LIST) {
    next if($pdf eq $OutPut);
    &Logit("Adding $pdf to $OutPut");
    prDoc($pdf);
}
prEnd();

很抱歉,如果我没有正确解释这一点,欢迎任何帮助和建议。

正在测试的新代码没有给出正确的顺序。

@PDFS = (<*l*.pdf>);
my %lsfOrder = (lua=>0, lsm=>1, lfw=>2);
@SORTED = map { $_->[0] } # Take just the original file name
     sort { 
        $a->[1] cmp $b->[1] ? 
          $a->[1] cmp $b->[1] : # compare by account id if different
          $lsfOrder{$a->[2]} <=> $lsfOrder{$b->[2]} 
      }
      map {
        [ $_, split('.', $_) ] # split into id/type once at the beginning
      } @PDFS;

prFile($OutPut);
for my $pdf (@SORTED) {
   next if($pdf eq $OutPut);
   &Logit("Adding $pdf to $OutPut");
   #print "Adding $pdf to $OutPut\n";
       prDoc($pdf);
}
    prEnd();

【问题讨论】:

    标签: perl sorting


    【解决方案1】:

    Perl 排序将一个代码块作为它的第一个参数来控制排序。定义了两个特殊变量,“$a”和“$b”,它们是要比较的两个元素。从那里,您将使用cmp&lt;=&gt; 比较字符串的不同部分并返回a 是否小于、大于或等于b。 sort 函数根据其内部排序算法从您的列表中选择 $a 和 $b。例如:

    @SORTED = sort {
      my @a = split ".", $a;
      my @b = split ".", $b;
      if ($a[0] cmp $b[0] != 0) { return $a[0] cmp $b[0] }
      my %lsfOrder = (lau=>0, lsm=>1, lad=>2, lfs=>3, lbe=>4);
      my $lsfA = $lsfOrder{$a[1]};
      my $lsfB = $lsfOrder{$b[1]};
      return $lsfA <=> $lsfB;
    } @PDFS;
    

    上面的代码分割了“.”上的文件名。然后它比较第一个元素(帐户 ID),如果它们不相同,则返回该比较的结果。否则返回比较报告类型的结果。它按照您给定的顺序将 lsf 转换为整数,然后比较这些整数。

    编辑:Joe Z 对加速有很好的建议。总结一下:

    my %lsfOrder = (lau=>0, lsm=>1, lad=>2, lfs=>3, lbe=>4);
    @SORTED = map { $_->[0] } # Take just the original file name
              sort { 
                $a->[1] cmp $b->[1] ? 
                  $a->[1] cmp $b->[1] : # compare by account id if different
                  $lsfOrder{$a->[2]} <=> $lsfOrder{$b->[2]} # otherwise, compare by report type in specific order
              }
              map {
                [ $_, split('.', $_) ] # split into id/type once at the beginning
              } @PDFS;
    

    【讨论】:

    • 虽然这种方法有效,但我建议将my %lsfOrder 移出sort { } 块,因为您正在为每个键比较构建该哈希。另外,我意识到您为了算法清晰而写了my $lsfA ...my $lsfB ...,但这些又带来了开销。如果您要对大列表进行排序,可能只想直接比较 $lsfOrder{$a[1]} 和 $lsfOrder{$b[1]}。最后,每次做split也可以加起来。
    • 将我的 cmets 组合成一个简洁的重写:@SORTED = map { $_-&gt;[0] } sort { $a-&gt;[1] cmp $b-&gt;[1] ? $a-&gt;[1] cmp $b-&gt;[1] : $lsfOrder{$a-&gt;[2]} &lt;=&gt; $lsfOrder{$b-&gt;[2]} } map { [ $_, split('.', $_) ] } @PDFS;
    • 谢谢大家,除非我对@SORTED 进行反向排序,否则它不会给我正确的顺序。 20130809:12:42:10 将 c09968.lfw.pdf 添加到 test20130809-3.pdf 20130809:12:42:10 将 c09968.lsm.pdf 添加到 test20130809-3.pdf 20130809:12:42:10 添加 c09968.lua。 pdf 到 test20130809-3.pdf 所需的输出将是 lua.pdf lsm.pdf lfw.pdf。想法?
    • 请注意,'lfw' 不在 lsfOrder 散列中。您应该将其添加到正确的位置(以及您可能拥有的任何其他位置)。此外,请检查您的所有as 和bs 是否正确,因为上面的代码应该将“lua”放在“lsm”之前。最后,您可以通过将排序块中的所有as 更改为bs 和bs 更改为as 来反转排序。
    • 不是我只处理三个报告,所以我的 lstOrder 是我的 %lsfOrder = (lau=>0, lsm=>1, lfw=>2);我会检查 A&Bs
    猜你喜欢
    • 2011-07-14
    • 2015-05-18
    • 2019-04-10
    • 1970-01-01
    • 2012-07-28
    • 2019-03-30
    • 2018-01-14
    • 2015-05-19
    • 1970-01-01
    相关资源
    最近更新 更多