【问题标题】:Custom array sort in perlperl中的自定义数组排序
【发布时间】:2011-02-25 18:07:30
【问题描述】:

我有一个 perl 待办任务数组,如下所示:

@todos = (
  "1 (A) Complete online final @evm4700 t:2010-06-02",
  "3 Write thank-you t:2010-06-10",
  "4 (B) Clean t:2010-05-30",
  "5 Donate to LSF t:2010-06-02",
  "6 (A) t:2010-05-30 Pick up dry cleaning",
  "2 (C) Call Chris Johnson t:2010-06-01"
);

第一个数字是任务的 ID。如果任务旁边有 ([A-Z]),则定义了任务的优先级。我想要做的是以将优先项放在首位的方式对任务数组进行排序(并按优先级降序排列,从 A - Z):

@todos = (
  "1 (A) Complete online final @evm4700 t:2010-06-02",
  "6 (A) t:2010-05-30 Pick up dry cleaning",
  "4 (B) Clean t:2010-05-30",
  "2 (C) Call Chris Johnson t:2010-06-01"
  "3 Write thank-you t:2010-06-10",
  "5 Donate to LSF t:2010-06-02",
);

我不能使用常规的sort(),因为任务旁边有这些 ID,所以我假设需要某种定制的排序子例程。但是,我对如何在 perl 中有效地做到这一点的了解很少。

谢谢大家。

【问题讨论】:

    标签: perl sorting arrays


    【解决方案1】:

    听起来你想要Schwartzian transform

    @todos =
        map  { $_->[0] }
        sort { $a->[1] cmp $b->[1] or $a->[0] cmp $b->[0] }
        map  { [ $_, /^\d+ \(([[:alpha:]])\)/ ? $1 : "[" ] }
        @todos;
    

    “[”是“Z”后面的字符;将此“优先级”赋予其他没有优先级的项目会将它们排序在优先级之后。

    或者,也许更容易掌握:

    @todos =
        map { substr $_, 1 }
        sort
        map { (/^\d+ \(([[:alpha:]])\)/ ? $1 : "[") . $_ }
        @todos;
    

    【讨论】:

    • @Sean :虽然 Schwartzian 变换很时髦(并且适用),但很难理解,尤其是考虑到 OP 是初学者。
    • @Sean - 这是一个很酷的解决方案;谢谢。你需要逃避] ater :alpha: 吗? @Zaid - 即使我是初学者,@Sean 也给了我解释 Schwartzian 变换的链接,所以我可以理解它。 :)
    • @ABach:不,不需要转义;这是一个 POSIX 字符类。 (请参阅 perlre 手册页。) ...但我确实打错了字(“[:alpha:]]”而不是“[[:alpha:]]”,我刚刚修复了它。
    • @Sean - 看起来很棒。谢谢。 :)
    • 10 应该在9 之后(你需要数字排序)
    【解决方案2】:

    这是一个相当明确的版本:

    my @sorted_todos = sort {
        my ($right_prio) = ($b =~ /^\d+\s+\(([A-Z])\)/);
        return -1 unless defined $right_prio;
        my ($left_prio) = ($a =~ /^\d+\s+\(([A-Z])\)/);
        return 1 unless defined $left_prio;
        return $left_prio cmp $right_prio;
    } @todos;
    

    【讨论】:

      【解决方案3】:

      这里是固定的@Sean's solution,它对任务 ID 使用数字排序(因此第 10 个任务应该排在第 9 个之后):

      my @sorted_todos =  map  { $_->[0] }
          sort { $a->[1][1] cmp $b->[1][1] # A
                             || 
                 $a->[1][0] <=> $b->[1][0] # 1
          } map  { [ $_, /^(\d+) \(([[:alpha:]])\)/ ? [$1, $2] : [0, "zz"]] }  @todos;
      

      【讨论】:

      • 对于这个小问题,编辑肖恩的答案似乎就足够了。你并不完全缺乏代表。
      • @rjh:阅读 cmets 到 Sean 的答案,OP 不想要我提供的解决方案,所以我编辑 Sean 的答案是错误的。另一方面,我的回答对于将来会搜索“perl 中的自定义排序”的其他人很有用。
      【解决方案4】:
      use Sort::Key 'keysort';
      
      my @sorted = keysort { /^\d+\s+\(([A-Z])\)/ ? $1 : 'ZZ' } @todos;
      

      【讨论】:

        【解决方案5】:

        更简单的解决方案:

        sort {($a =~ /\((.)\)/)[0] cmp ($b =~ /\((.)\)/)[0]} @todos;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-05-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-04
          • 1970-01-01
          • 2010-10-23
          • 1970-01-01
          相关资源
          最近更新 更多