使用Perl对子数组值进行排序

时间:2013-12-23 23:32:04

标签: perl sorting

我有以下数组模式:   2个字母x个数字2个字母y个数字2个字母z个数字等等。

我希望对字母之间的数字进行排序,并保持字母不变。

例如:

 a b 3 5 7 4 d c 6 3 2    

将成为

 a b 3 4 5 7 c d 2 3 6

我如何在Perl中实现它?

我试图通过

保存字母的索引
my %index=();
my $count =0 ;
foreach (@arr ) {

if($_~=/[a-zA-Z]) {
$index{$_}=$count;
}
$count++

}

然后尝试用splice替换这些部分。

此外,我尝试了以下似乎有效:

my @a =qw(a b 1 3 5 3  c d 4 5 2);

my (@b,@c) =();
my $count=0;
foreach (@a) {
    if($_=~/[A-Za-z]/){
        push @b,sort @c;
        push @b,$_;
        if($count%2==0) { 
           @c=();
        }
        $count++;
    }
    else {
        push @c,$_;
    }
}

我想知道是否有更高效和Perlish风格的方式来做到这一点?

2 个答案:

答案 0 :(得分:1)

一种方法是循环数组一次,保持序列中遇到的第一个数字的索引。遇到字符(意味着数字序列已结束),然后直接在该数组切片中对数字序列进行排序

use strict;
my @arr = ('a','b',3,5,7,4,'d','c',6,3,2);

my $first = -1;
for (my $i = 0; $i < @arr; $i++) {
  if($arr[$i] =~ m/[a-z]/i) {
    next if ($first == -1);
    @arr[$first..($i-1)] = sort {$a<=>$b} @arr[$first..($i-1)];
    $first = -1;
  } elsif ($first == -1) {
    $first = $i;
  } 
}
#one last time after the loop
@arr[$first..(@arr-1)] = sort {$a<=>$b} @arr[$first..(@arr-1)] if ($first != -1);

print join(',',@arr)."\n";

答案 1 :(得分:0)

这更令人满意吗?

#!/usr/bin/env perl
use strict;
use warnings;

my @list = ('a', 'b', '3', '5', '7', '4', 'd', 'c', '6', '3', '2');

for (my $i = 0; $i < scalar(@list); $i++)
{
    if ($list[$i] =~ m/[[:alpha:]]/)
    {
        # Assume $list[$i+1] exists and is alphabetic too!
        @list[$i..$i+1] = sort @list[$i..$i+1];
        $i++;
    }
}

print "@list\n";

概念是当当前条目是字母时,下一个条目也必须是,所以对该数组的片进行排序并增加$i,以便不单独处理第二个字母字符。示例输出为:

a b 3 5 7 4 c d 6 3 2

我对排序中的重复切片并不完全满意,但我不确定在使用sort时是否有办法避免这种情况。

当然,因为它是Perl,所以有不止一种方法(TMTOWTDI),所以这两者也产生了正确的答案。我不确定哪个不那么怪诞。我可能错过了一些交换两个变量的惯用方法。

#!/usr/bin/env perl
use strict;
use warnings;

my @list = ('a', 'b', '3', '5', '7', '4', 'd', 'c', '6', '3', '2');

for (my $i = 0; $i < scalar(@list); $i++)
{
    if ($list[$i] =~ m/[[:alpha:]]/)
    {
        ($list[$i], $list[$i+1]) = ($list[$i+1], $list[$i]) if ($list[$i] gt $list[$i+1]);
        $i++;
    }
}

print "@list\n";

由于对列表元素的三次引用,该交换行很可怕。

#!/usr/bin/env perl
use strict;
use warnings;

my @list = ('a', 'b', '3', '5', '7', '4', 'd', 'c', '6', '3', '2');

for (my $i = 0; $i < scalar(@list); $i++)
{
    if ($list[$i] =~ m/[[:alpha:]]/)
    {
        my($x,$y) = (\$list[$i], \$list[$i+1]);
        ($$x, $$y) = ($$y, $$x) if ($$x gt $$y);
        $i++;
    }
}

print "@list\n";

交换行很可怕,因为它明确地交换显式引用。