【问题标题】:How can I select certain elements from a Perl array?如何从 Perl 数组中选择某些元素?
【发布时间】:2010-10-12 14:37:09
【问题描述】:

我想搜索一个数组中与另一个数组中的元素具有相同起始字符集的所有元素。说清楚:

@array = ("1a","9","3c");
@temp =("1","2","3");

我只想打印 1a 和 3c。当我尝试使用以下程序时,它会打印出数组中的所有元素,而不是我想要的两个:

foreach $word (@temp)
{
    if( grep /^$word/ , @array) 
    {
        print $_;
    }
}

我们将不胜感激。

【问题讨论】:

  • 你应该接受你以前的一些问题的答案:)
  • 完成。不知道我必须这样做。
  • 我建议您使用my 声明变量,例如my @array = (..), foreach my $word (@temp) {..} 并启用严格和警告

标签: regex perl grep


【解决方案1】:

此答案将满足 OP 的要求,并通过使用哈希查找防止任何重复项在屏幕上打印。

#!/usr/bin/perl

use strict;
use warnings;

my @array = ("1a","9","3c","3c");
my @temp =("1","2","3");

my %dups_hash;

for my $w (@temp) {
    my ($match) = grep /^$w/, @array;

    # Need to check if $match is defined before doing the hash lookup.
    # This suppresses error messages for uninitialized values; if defined($match) is
    #  false, we short circuit and continue in the loop.
    if(defined($match) && !defined($dups_hash{$match})) {
        print $match;
    }
}

【讨论】:

    【解决方案2】:

    如果你想成对匹配元素,你可以这样做:

    for my $i (0..$#array) {
        print $array[$i], "\n" if $array[$i] =~ /^$temp[$i]/
    }
    

    否则你可以使用grep:

    for my $i (0..$#array) {
        print "$array[$i]\n" if grep /^$temp[$i]/, @array;
    }
    

    【讨论】:

    • 我认为这太严格了...... OP 只是说如果元素以另一个数组中的任何元素开头,他希望打印该元素。这强加了一对一的映射。
    • 由于某种原因我无法撤消我的 -1...您能帮我一个忙并再次编辑它以便我撤消它吗?
    • 带有 grep 的第二个仍然不能满足 OP 的要求。它会打印您用于 grep 的单词,而不是数组中的值。
    【解决方案3】:

    对于这类问题,诀窍是不要过度扫描数组。我认为 Knuth 写了一整本书。 :) 通常,我们会陷入这些情况,因为我们过于拘泥于我们首先尝试的事情。

    您可以从要搜索的所有模式中构造一个正则表达式,然后扫描一次数组:

    use Regexp::Assemble;
    
    my @array = qw( 1a 9 3c );
    my @temp  = qw( 1 2 3 );
    
    my $ra = Regexp::Assemble->new;
    $ra->add( @temp );
    
    my $pattern = $ra->re;
    print "pattern is [$pattern]\n";
    
    print join ' ', grep /\A$pattern/ , @array;
    

    当你不关心模式的哪一部分匹配时,这种方法会起作用。

    【讨论】:

      【解决方案4】:

      当我尝试使用以下内容时 程序打印出所有元素 在数组中而不是两个我 想要。

      不,它没有。正如所写,它什么也不打印。严格打开后,它会打印“全局符号“$temp”需要显式包”。

      修正了那个明显的错字并打开警告,它会打印两次“使用未初始化的值 $_ in print”。

      请不要浪费我们的时间,向我们展示要么不能编译的代码就不能按照你说的那样做。不要在此站点中重新输入代码 - 剪切并粘贴您正在使用的实际代码。

      解决您的问题的方法如下:

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      my @array = ("1a","9","3c");
      my @temp =("1","2","3");
      
      foreach my $word (@temp) {
        print grep /^$word/ , @array;
      }
      

      但可能有更有效的方法。

      【讨论】:

      • 这可能会导致重复(如果@temp 有多个以相同开头的元素,因此可以将@array 中的某些内容与每个元素匹配)。
      • 感谢您的回答。我确实复制粘贴了“实际代码和输出”。尽管我知道它是一个标准,但我不使用严格。我只是使用 perl 进行快速字符串操作,尽管我知道我应该使用 strict。
      【解决方案5】:
      map { print "$_\n" } grep { my $a = $_; grep {$a =~ /^$_/} @temp } @array
      

      基本上,外部grep 选择@temp 中的一个或多个元素与内部正则表达式匹配的元素——也就是说,它选择所有以其中一个(或多个)元素开头的元素@temp.

      【讨论】:

      • 嗯..快速跟进..如果您只想打印第一个匹配项怎么办?
      【解决方案6】:

      如果 grep 返回空列表,避免出现空行:

      #!/usr/bin/perl
      use strict;
      use warnings;
      use 5.10.1;
      
      my @array = qw(1a 9 3c 1g);
      my @temp =(1, 2, 3);
      foreach my $word(@temp) {
        my @l = grep{/^$word/}@array;
        say "@l" if @l;
      }
      

      输出:

      1a 1g
      3c
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-21
        • 2018-04-28
        • 2018-06-15
        • 1970-01-01
        • 2020-07-09
        • 1970-01-01
        • 1970-01-01
        • 2020-08-01
        相关资源
        最近更新 更多