【问题标题】:Splitting an array in Perl在 Perl 中拆分数组
【发布时间】:2014-04-06 09:57:01
【问题描述】:

我有一个类似的数组

@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);
    }
}

它不返回任何东西。

【问题讨论】:

  • 我看到你的例子有 2 个问题。 1.您的迭代器变量是$item,但您将另一个变量$add 推送到数组中。 2. 你只推到一个阵列上。您不能推入一个数组并期望值转到 2 个数组。

标签: arrays perl split


【解决方案1】:

循环遍历列表,同时使用数组引用来决定要填充的目标数组。

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 );
    }
}  

【讨论】:

  • 很好,但是一次移动一个元素非常慢。
  • 我不认为这是个问题。
【解决方案2】:

这样做的唯一方法是搜索第一个空白元素。您可以像这样使用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;
}

并将对firstidx的调用更改为my $i = first_blank_idx(\@tmp)

【讨论】:

    【解决方案3】:
    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;
    

    【讨论】:

      【解决方案4】:

      您可以使用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] 中。

      【讨论】:

        【解决方案5】:

        您可以使用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'
        ]
        

        【讨论】:

          【解决方案6】:

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

          如果 Perl 5 安装的是版本 14 或更高版本,那么 push 接受一个数组 reference 作为它的第一个参数,因此可以使用这样的状态变量巧妙地编写数组之间的切换 p>

          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 }, $_;
          

          【讨论】:

            猜你喜欢
            • 2014-06-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多