perl中的自定义数组排序

时间:2010-05-30 18:19:11

标签: perl sorting arrays

我有一系列per-do任务看起来像这样:

@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",
);

由于任务旁边的ID,我无法使用常规sort(),所以我假设需要某种自定义排序子程序。但是,我对如何在perl中高效执行此操作的知识很少。

谢谢,所有。

5 个答案:

答案 0 :(得分:12)

听起来你想要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;

答案 1 :(得分:3)

这是一个相当明确的工作方式的版本:

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;

答案 2 :(得分:0)

这是固定的@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;

答案 3 :(得分:0)

use Sort::Key 'keysort';

my @sorted = keysort { /^\d+\s+\(([A-Z])\)/ ? $1 : 'ZZ' } @todos;

答案 4 :(得分:0)

更简单的解决方案:

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