在Perl中拆分数组

时间:2014-03-04 17:44:20

标签: arrays perl split

我有一个类似

的数组
@tmp = ('value1-1', 'value1-2', 'value1-3', '', 'value2-1', 'value2-2', 'value2-3')

在看到值为空''后,如何将数组分成两部分?

这样输出应该是这样的

@value1=('value1-1','value1-2','value1-3');
@value2=('value2-1','value2-2','value2-3');

我试过这种方式

foreach $item(@tmp){
    unless($add == ''){
         #print $add;
         push (@value,$add);
    }
}

它不会返回任何内容。

6 个答案:

答案 0 :(得分:6)

在使用数组引用时循环遍历列表,以确定要填充的目标数组。

my @value1;
my @value2;

my @tmp = ('value1-1', 'value1-2', 'value1-3', '', 'value2-1', 'value2-2', 'value2-3');

my $target = \@value1;
for my $val ( @tmp ) {
    if ( $val eq '' ) {
        $target = \@value2;
    }
    else {
        push( @{$target}, $val );
    }
}  

答案 1 :(得分:3)

执行此操作的唯一方法是搜索第一个空白元素。您可以使用List::MoreUtils中的firstidx功能,方便地执行此操作

use strict;
use warnings;

use List::MoreUtils 'firstidx';

my @tmp = ('value1-1', 'value1-2', 'value1-3', '', 'value2-1', 'value2-2', 'value2-3');

my $i = firstidx { length == 0 } @tmp;
my @value2 = @tmp;
my @value1 = splice @value2, 0, $i;
shift @value2;

use Data::Dump;
dd \@value1, \@value2;

<强>输出

(
  ["value1-1", "value1-2", "value1-3"],
  ["value2-1", "value2-2", "value2-3"],
)

该模块不是核心模块,因此您可能不希望安装它。您可以使用

编写自己的辅助函数
sub first_blank_idx {
  my ($arr) = @_;
  length $arr->[$_] or return $_ for 0 .. $#$arr;
  return -1;
}

并将通话更改为firstidxmy $i = first_blank_idx(\@tmp)

答案 2 :(得分:2)

use strict;
use warnings;

my @tmp = ('value1-1', 'value1-2', 'value1-3', '', 'value2-1', 'value2-2', 'value2-3');

my @blanks = grep {$tmp[$_] eq ''} 0 .. $#tmp;

die "No blank elements" unless @blanks;
warn "More than one blank" if @blanks > 1;

my @value1 = @tmp[0 .. $blanks[0]-1];
my @value2 = @tmp[$blank[0]+1 .. $#tmp];

use Data::Dump;
dd \@value1, \@value2;

答案 3 :(得分:2)

您可以使用List::MoreUtils中的part对数组进行分区:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;
use List::MoreUtils qw(part);

my @array = (
    'foo', 'bar', 'baz', '',
    'alpha', 'beta', 'gamma', '',
    'apple', 'pear', 'banana'
);

my $index = 1;
my @parts = part { $_ eq '' ? $index++ && 0 : $index } @array;

print Dumper \@parts;

输出:

$VAR1 = [
          [
            '',
            ''
          ],
          [
            'foo',
            'bar',
            'baz'
          ],
          [
            'alpha',
            'beta',
            'gamma'
          ],
          [
            'apple',
            'pear',
            'banana'
          ]
        ];

从示例中可以看出,这适用于任意数量的分区,而不仅仅是两个分区。结果存储在一个数组数组中,空记录('')存储在$array[0]中。

答案 4 :(得分:1)

您可以使用splitjoin来做到这一点非常简洁:

use strict; 
use warnings; 

my @tmp = 
   ('value1-1', 'value1-2', 'value1-3', '', 'value2-1', 'value2-2', 'value2-3');

# note that since the pivot value is empty there with be two && in its place
# we can split on that
my ($values1, $values2) = 
   map { [split '&', $_] } split('&&', join('&', @tmp));

__END__
[
   'value1-1',
   'value1-2',
   'value1-3'
],
[
   'value2-1',
   'value2-2',
   'value2-3'
]

答案 5 :(得分:1)

正如 Andy Lester 在他的评论中指出的那样,除非数组很大,否则原始@tmp数组的逐项过滤可能足够快。

如果Perl 5安装版本为14或更高版本,则push接受数组引用作为其第一个参数,因此可以使用像这样的状态变量整齐地编写数组之间的切换

use strict;
use warnings;
use 5.014;

my @tmp = ('value1-1', 'value1-2', 'value1-3', '', 'value2-1', 'value2-2', 'value2-3');

my (@value1, @value2);
my $split;

for (@tmp) {
  if (length or $split) {
    push $split ? \@value2 : \@value1, $_;
  }
  else {
    $split = 1;
  }
}

use Data::Dump;
dd \(@value1, @value2);

<强>输出

(
  ["value1-1", "value1-2", "value1-3"],
  ["value2-1", "value2-2", "value2-3"],
)

在早期版本中,必须取消引用该数组,因此push调用将变为

push @{ $split ? \@value2 : \@value1 }, $_;