Question

I have two arrays that are associated. The first has what would be a "key" in a hash, the second has the "value". There are multiple instances of each "key" in the array, and the value associated with each key can be either yes, or no. A quick example:

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

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

Notice that there are both yes and no values associated with the "key" NET1020.

I need to use @1 to 1st look for duplicates and remove them from both arrays, and if one of the values is no in @2, then that needs to be the value for the "key" in @1. If not, then the value can be yes. Basically what I need to end up with is:

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

I hope I have been clear enough in my explanation. I am a perl novice and am at a loss as to where to even start.

Thanks for you help.

Was it helpful?

Solution 2

It isn't clear whether you are starting with Perl arrays or simple comma-separated strings. I am also unsure whether you want the resultant hash values capitalised as you show, or the same as the input values.

This short program will do what you need. It simply assigns hash elements using each key from @a1 and an initial value of yes. Thereafter, if a corresponding no is encountered in @a2 then the element's value is set to 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;

output

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

OTHER TIPS

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;

You shouldn't work with yes and no or Yes and No. This solution converts yes and no to a more appropriate true and false on input. If you want to output Yes and No for true and false, you'd handle that on output, as shown.

You can even see the benefit of using true and false in this little job. It works by ANDing the flags of the entries with the same name. (False wins out when ANDing. True wins out when ORing.)

Is the order of the array content important?

If not, i would suggest to use a hash:

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

Note: code untested and not validated

Just loop through the values and add to/update your hash as needed.

1.If the key already exists, only update it if the existing value is not 'no'

2 If the key doesn't exist, add it to the hash

#!/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'
};

If there were no duplicates you could do this in a single line with a hash-slice:

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

I had to modify your list to work better as Perl. You gave a multi-line string and not an array. Basically, my approach is pretty standard CPAN. List::Util and List::MoreUtils.

zip creates a order-based correspondence between lists. And pairs allows you to deal with a key-value pair as ( $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
;

Of course, pairwise might be cleaner:

use List::MoreUtils qw<pairwise>;
...
pairwise { 
    $hash{ $a } = $b unless ( $hash{ $a } // '' ) eq 'no'; 
} @_1, @_2
;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top