Search code examples
perlperl-data-structures

compare 2 arrays for intersect diff and commmon values


I want to compare 2 arrays and want diff , common and intersect values but below code is not working. No error message all I can see Array as an value although I am calling $difference[0] so I doubt if the code is correct.

   sub updatedevice() {
my $n = {};

my $Device_LINK = $server->object("ICF_PersistentDataSet",$devicelinks);
my $Temp_Device_LINK = $server->object("ICF_PersistentDataSet",$tempdevicelinks);

my @current_devicelist = @{ $Device_LINK->invoke("get") };
my @temp_devicelist = @{ $Temp_Device_LINK->invoke("get") };

my %temp_list;
my %current_list;

my $size = @current_devicelist;
for ($n=0; $n < $size; $n++) {
       our $device=$current_devicelist[$n][0];
        DEBUG( "DEBUG: - devicelinks  values $device  " );   --- > able to print this value of device "ABC-DCFE41->90"

my $size = @temp_devicelist;
for ($n=0; $n < $size; $n++) {
      our $tempdevicelinks=$temp_devicelist[$n][0];
DEBUG( "DEBUG: - temp plc links values $tempdevicelinks " ); --- > able to print this value of device "GHJKL-poiu->78"

my %count = ();
foreach my $device (@current_devicelist, @temp_devicelist) {
    $count{$device}++;
}
my @difference = grep { $count{$_} == 1 } keys %count;
my @intersect  = grep { $count{$_} == 2 } keys %count;
my @union      = keys %count;

DEBUG( "DEBUG: - difference links values $difference[0] " );
DEBUG( "DEBUG: - intersect links values $intersect[0] " );
DEBUG( "DEBUG: - union links values $union[0] " );

                }
        }
}

Solution

  • The problem is that you're assigning array reference (returned from invoke to an array).

    Your statement of "see 'array' as a value" is a dead giveaway that you're manipulating array references (instead of arrays) - when printed, they turn into strings like this: 'ARRAY(0x349014)'

    The problem is that you're taking an array reference (a scalar), and assigning it to an array - which imposes list context on your value, and turns that scalar into a list with its only element being that scalar. Thus you simply store the array reference as the first and only element of the array - instead of storing the list of values that's being referenced like you intended.


    To demonstrate:

    my @current_devicelist = (1,3); # Assign real arrays
    my @temp_devicelist = (2,3);
    
    my %count = ();
    foreach my $device (@current_devicelist, @temp_devicelist) {
        $count{$device}++;
    }
    
    my @difference = grep { $count{$_} == 1 } keys %count;
    my @intersect  = grep { $count{$_} == 2 } keys %count;
    my @union      = keys %count;
    
    use Data::Dumper;
    print Data::Dumper->Dump([\@difference, \@intersect, \@union]
                            ,["difference","intersect","union"]);
    

    This prints:

    $difference = [
                    '1',
                    '2'
                  ];
    $intersect = [
                   '3'
                 ];
    $union = [
               '1',
               '3',
               '2'
             ];
    

    Now, if you mimique what your code was doing instead by changing the first 2 lines to:

    my @current_devicelist = [1,3]; # Assign reference
    #    Works the same as if you said 
    # my @current_devicelist = ([1,3]);
    #    or
    # my $current_devicelist[0] = [1,3];
    
    my @temp_devicelist = [2,3];
    

    ... you get:

    $difference = [
                    'ARRAY(0x349014)',
                    'ARRAY(0x349114)'
                  ];
    $intersect = [];
    $union = [
               'ARRAY(0x349014)',
               'ARRAY(0x349114)'
             ];
    

    To fix your problem, you can do one of 4 things:

    1. Simply dereference your returned array references, using @{} dereference:

      my @current_devicelist = @{ $Device->invoke("get")      };
      my @temp_devicelist    = @{ $Temp_Device->invoke("get") };
      
    2. Change invoke() method - if you can - to return an array instead of array reference:

      # Old code: 
      # return $myArrRef;
      # New Code:
      return @$myArrRef;
      
    3. Change invoke() method - if you can - to return an array OR an arrayref based on context (using wantarray):

      # Old code: 
      # return $myArrRef;
      # New Code:
      return wantarray : @$myArrRef : $myArrRef;
      
    4. Change your code to use array references

      my $current_devicelist = $Device->invoke("get");
      my $temp_devicelist = $Temp_Device->invoke("get");
      
      my %count = ();
      foreach my $device (@$current_devicelist, @$temp_devicelist) {
          $count{$device}++;
      }