【问题标题】:Finding elements of an array that match elements of a second array查找与第二个数组元素匹配的数组元素
【发布时间】:2015-05-23 16:33:59
【问题描述】:

我有两个数组 @uarts 和 @txd,看起来像这样

@uarts = qw(uart_1 uart_10 uart_3 uart_9 ); 
@txd = qw(PIO_uart_1 PIO_2_uart_1 PIO_uart_3 PIO_uart_10 PIO_uart_5 PIO_uart_9 PIO_uart_7);

我只想从包含@uarts 的任何元素的@txd 中提取那些元素。我为其编写的代码如下,但不起作用。

my @array;
for (my $i = 0 ; $i <= $#uarts ; $i++) {
  @array = grep { $_ =~ /$uarts[$i]/ } (@txd);
  print "@array\n";
}

【问题讨论】:

  • 请学习格式化您的 Perl 代码,使其可读。在这种情况下,我已经为您完成了,但是如果您发布可理解的代码,它将使试图帮助您的人以及您自己受益。
  • 这次我做了缩进。对不起,我听不懂
  • 啊,好吧。嗯,它肯定比以前更好,但是你有一个不寻常的格式样式,大括号缩进一级,内容再次缩进。在for 之后看到一个空格以将其与函数调用区分开来也很好。查看perldoc perlstyle 了解最常见的标准

标签: arrays perl data-structures


【解决方案1】:

我必须诚实。我认为map 和grep 都很烦人,以至于如果你不熟悉 perl,请避开。它们并没有给你带来太多好处——它们看起来好像在降低代码的复杂性,但那是因为 grep 的循环是隐式的。所以你所做的只是让你的代码更难理解。

另外 - 我真的不喜欢 for 循环的风格 - 它 几乎 在 perl 中总是多余的 - 在上述情况下,您引用的唯一元素是当前元素(这是一个不同的无论您是访问“下一个”还是“上一个”元素)。

所以展开它:

foreach my $uart ( @uarts ) {
    foreach my $PIO ( @txd ) {
        if ( $PIO =~ m/$uart/ ) { 
            print "$PIO matches $uart\n";
        }
     }
 }

注意:这不会进行任何类型的唯一性测试,因此如果出现多个匹配项,您会被骗。

哦,打开use strict; 和use warnings;。你的数组声明是错误的。

my @uarts = qw ( uart_1 uart_10 uart_3 uart_9 );
my @txd   = qw ( PIO_uart_1 PIO_2_uart_1 PIO_uart_3 PIO_uart_10
                 PIO_uart_5 PIO_uart_9PIO_uart_7
);

我还要指出 - 您已将 @array 范围限定在循环之外,这可能意味着想要保留它。但是你每次迭代都会通过分配grep 的输出来破坏它。

我建议您在循环中使用@array,或者查看push/pop 和shift/unshift 作为从现有数组中添加和删除元素的方法。

【讨论】:

  • 如果你需要下一个/上一个元素,那么像 foreach my $i ( 0 .. $#my_array ) 这样的东西通常比传统的 C 风格的 for 循环更容易阅读
  • 其实我已经“使用严格;”和“使用警告;”已经和这些数组 uarts 和 txd 我没有在这里声明。这些在我之前的脚本行中的代码中。我只给出了从“my @array”开始的一小部分代码。
  • 对于您建议的代码,我想打印@txd 的匹配元素
【解决方案2】:
@uarts =(uart_1,uart_10,uart_3,uart_9 ); 
@txd =(PIO_uart_1,PIO_2_uart_1,PIO_uart_3,PIO_uart_10,PIO_uart_5,PIO_uart_9,PIO_uart_7);
my @array;
for(my $i=0;$i<=$#uarts;$i++ )
{
    @array=grep{$_=~/$uarts[$i]/}(@uarts);
    print "@array\n";
}

输出

uart_1 uart_10
uart_10
uart_3
uart_9

【讨论】:

    【解决方案3】:

    您可以通过将@array = grep{$_=~ /$uarts[$i]/}(@txd); 更改为push @array, grep{$_=~ /$uarts[$i]/}(@txd); 来修复您的代码。

    但是明智而有效的方法是准备一次匹配的正则表达式,然后在O(N+M)而不是O(N*M)中进行。

    use strict;
    use warnings;
    
    my @uarts = qw(uart_1 uart_10 uart_3 uart_9);
    my @txd
        = qw(PIO_uart_1 PIO_2_uart_1 PIO_uart_3 PIO_uart_10 PIO_uart_5 PIO_uart_9 PIO_uart_7);
    
    my @array = do {
        my $re = join '|', map quotemeta, @uarts;
        $re = qr/$re/;
        grep /$re/, @txd;
    };
    
    print "@array\n";
    

    【讨论】:

    • 我真的怀疑这是真的:你的答案经常有问题。例如,此代码与 OP 的原始代码存在相同的问题:它发现 @txd 的元素 包含 @uarts 中的任何字符串,而不是那些 以 其中任何一个。编译正则表达式以供一次性使用也没有意义,因为grep 行无论如何都会这样做。我早就放弃了对选票的追逐——那就是疯了!
    • 你是对的 $re = qr/$re/; 行是不必要的,但显式编译正则表达式只是习惯。我喜欢在代码中看到这个正则表达式从那时起就保持不变。我通常在不同的地方使用相同的正则表达式。
    【解决方案4】:

    您的代码按原样“有效”。你应该总是说出你所说的“不工作”的意思。

    我认为问题在于您的代码完全按照您的描述运行。它会找到 “来自 @txd 的那些元素,其中包含 @uarts 的任何元素” 而我认为您需要那些 以 中的任何字符串结尾的元素 @ 987654323@.

    就目前而言,您的程序输出

    PIO_uart_1 PIO_2_uart_1 PIO_uart_10
    PIO_uart_10
    PIO_uart_3
    PIO_uart_9
    

    所以当检查uart_1 时,它会找到PIO_uart_10,因为前者是后者的子字符串。要查找 end 与给定 uart 字符串的元素,您只需向正则表达式添加一个行尾锚,使其变为

    @array = grep { $_ =~ /$uarts[$i]$/ } (@txd)
    

    这会将输出更改为

    PIO_uart_1 PIO_2_uart_1
    PIO_uart_10
    PIO_uart_3
    PIO_uart_9
    

    我希望这是你想要的?

    但它可以写得更好一点。除非您特别需要索引,否则最好循环遍历数组的 contents,并且没有必要将 @array 设为全局变量(并且可以更好地调整它)所以这对你有用

    use strict;
    use warnings;
    
    my @uarts = qw(uart_1 uart_10 uart_3 uart_9 ); 
    my @txd = qw(PIO_uart_1 PIO_2_uart_1 PIO_uart_3 PIO_uart_10 PIO_uart_5 PIO_uart_9 PIO_uart_7);
    
    for my $uart ( @uarts ) {
      my @matches = grep /$uart\z/, @txd;
      print "@matches\n";
    }
    

    输出

    PIO_uart_1 PIO_2_uart_1
    PIO_uart_10
    PIO_uart_3
    PIO_uart_9
    

    【讨论】:

    • 正好我最后只需要使用 $ .. 谢谢 :)
    猜你喜欢
    • 2015-01-08
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 2019-01-05
    • 1970-01-01
    • 2021-11-03
    相关资源
    最近更新 更多