Perl - 在一个数组中删除重复项时,从另一个数组中弹出该元素

时间:2014-03-04 15:28:53

标签: arrays perl hash deduplication

我有两个关联的数组。第一个具有哈希中的“关键”,第二个具有“值”。数组中每个“键”有多个实例,与每个键关联的值可以是yes或no。一个简单的例子:

@1 = ('NET1020, NET0190, NET1020, NET0230,
       NET1020, NET1639, NET0820, NET1639');

@2 = ('yes, yes, no, no,
       yes, no, yes, no');

请注意,“密钥”NET1020有“是”和“否”值。

我需要使用@ 1到1st查找重复项并从两个数组中删除它们,如果其中一个值在@ 2中为no,那么它必须是@ 1中“key”的值。如果没有,那么值可以是。基本上我最终需要的是:

%1-2 = (
    "NET1020"  => "No", 
    "NET0190"  => "Yes",
    "NET0230"  => "No",
    "NET1639"  => "No",
    "NET0820"  => "Yes",
);

我希望我在解释中已经足够清楚了。我是一个perl新手,我甚至不知道从哪里开始。

谢谢你的帮助。

5 个答案:

答案 0 :(得分:2)

my @names = split /\s*,\s*/, 'NET1020, NET0190, NET1020, NET0230, NET1020, NET1639, NET0820, NET1639';
my @flags = map { $_ eq 'yes' }
            split /\s*,\s*/, 'yes, yes, no, no, yes, no, yes, no';

my %flags;
for (0..$#names) {
   if (exists($flags{ $names[$_] })) {
      $flags{ $names[$_] } &&= $flags[$_];
   } else {
      $flags{ $names[$_] } = $flags[$_];
   }
}

print($_, ": ", $flags{$_} ? "Yes" : "No", "\n")
   for sort keys %flags;

您不应该使用yesnoYesNo。此解决方案将yesno转换为更合适的true和false输入。如果你想输出YesNo为true和false,你可以在输出上处理它,如图所示。

您甚至可以在这项小工作中看到使用真与假的好处。它通过ANDing具有相同名称的条目的标志来工作。 (当ANDing时,False胜出。当ORing时,True胜出。)

答案 1 :(得分:0)

数组内容的顺序是否重要?

如果没有,我建议使用哈希:

    my %hash = ();
    for my $i (0 .. $#array1)
    {
          $hash{ $array1[$i] } =  $array2[$i]; 
    }
@filtered1 = keys %hash;
@filtered2 = values %hash;

注意:代码未经测试且未经过验证

答案 2 :(得分:0)

只需遍历这些值,然后根据需要添加/更新哈希值。

1.如果密钥已存在,只有在现有值不是“否”时才更新

2如果密钥不存在,请将其添加到哈希

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

use Data::Dumper;

my @arr1 = 
   qw(NET1020 NET0190 NET1020 NET0230 NET1020 NET1639 NET0820 NET1639);
my @arr2 = 
   qw(yes yes no no yes no yes no);

my %h;
KEY:
foreach my $i ( 0 .. $#arr1 ) {
   # get the values out of your parallel arrays
   my $key = $arr1[$i];
   my $val = $arr2[$i];

   # if the key is already in your hash and does not have this value
   if (exists $h{$key} && $h{$key} ne $val) {
      # don't change the key if the value is currently 'no'
      next KEY if lc $h{$key} eq 'no';

      # update if the value was not yes, meaning this is going from yes -> no
      $h{$key} = $val;
   }

   # if the key didn't exist already add it
   $h{$key} = $val;
}
print Dumper \%h;

__END__   
{ 'NET0190' => 'yes',
  'NET1639' => 'no',
  'NET0230' => 'no',
  'NET0820' => 'yes',
  'NET1020' => 'no'
};

如果没有重复项,您可以使用hash-slice在一行中执行此操作:

my %h; 
@h{@arr1} = @arr2; 

答案 3 :(得分:0)

我必须修改你的列表才能更好地用作Perl。你给了一个多行字符串而不是数组。基本上,我的方法是非常标准的CPAN。 List::UtilList::MoreUtils

zip在列表之间创建基于订单的对应关系。 pairs允许您将键值对作为( $a, $b )处理。

use strict;
use warnings;
use List::Util      qw<pairmap>;
use List::MoreUtils qw<zip>;

my @_1 =  split /,\s*/ms, 
      ('NET1020, NET0190, NET1020, NET0230,
       NET1020, NET1639, NET0820, NET1639')
      ;

my @_2 = split /,\s*/ms, 
       ('yes, yes, no, no,
       yes, no, yes, no')
       ;
my %hash;
pairmap { 
    $hash{ $a } = $b unless ( $hash{ $a } // '' ) eq 'no'; 
} zip @_1, @_2
;

当然,pairwise可能更清洁:

use List::MoreUtils qw<pairwise>;
...
pairwise { 
    $hash{ $a } = $b unless ( $hash{ $a } // '' ) eq 'no'; 
} @_1, @_2
;

答案 4 :(得分:0)

目前尚不清楚您是从Perl数组开始还是以逗号分隔的简单字符串开头。我也不确定您是否希望结果哈希值在显示时大写,或者与输入值相同。

这个简短的程序将满足您的需求。它只使用@a1中的每个键和初始值yes来分配哈希元素。此后,如果在no中遇到相应的@a2,则该元素的值将设置为no

use strict;
use warnings;

my @a1 = qw{  NET1020 NET0190 NET1020 NET0230 NET1020 NET1639 NET0820 NET1639  };
my @a2 = qw{  yes     yes     no      no      yes     no      yes     no       };

my %data;
for my $i (0 .. $#a1) {
  my $key = $a1[$i];
  $data{$key} = 'yes' unless $data{$key};
  $data{$key} = 'no' if $a2[$i] eq 'no';
}

use Data::Dump;
dd \%data;

<强>输出

{
  NET0190 => "yes",
  NET0230 => "no",
  NET0820 => "yes",
  NET1020 => "no",
  NET1639 => "no",
}