In Perl, is there a built in way to compare two arrays for equality?

后端 未结 13 2394
无人及你
无人及你 2020-11-27 17:08

I have two arrays of strings that I would like to compare for equality:

my @array1 = (\"part1\", \"part2\", \"part3\", \"part4\");
my @array2 = (\"part1\", \         


        
13条回答
  •  伪装坚强ぢ
    2020-11-27 17:29

    There is the new smart match operator:

    #!/usr/bin/perl
    
    use 5.010;
    use strict;
    use warnings;
    
    my @x = (1, 2, 3);
    my @y = qw(1 2 3);
    
    say "[@x] and [@y] match" if @x ~~ @y;
    

    Regarding Array::Compare:

    Internally the comparator compares the two arrays by using join to turn both arrays into strings and comparing the strings using eq.

    I guess that is a valid method, but so long as we are using string comparisons, I would much rather use something like:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use List::AllUtils qw( each_arrayref );
    
    my @x = qw(1 2 3);
    my @y = (1, 2, 3);
    
    print "[@x] and [@y] match\n" if elementwise_eq( \(@x, @y) );
    
    sub elementwise_eq {
        my ($xref, $yref) = @_;
        return unless  @$xref == @$yref;
    
        my $it = each_arrayref($xref, $yref);
        while ( my ($x, $y) = $it->() ) {
            return unless $x eq $y;
        }
        return 1;
    }
    

    If the arrays you are comparing are large, joining them is going to do a lot of work and consume a lot of memory than just comparing each element one by one.

    Update: Of course, one should test such statements. Simple benchmarks:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Array::Compare;
    use Benchmark qw( cmpthese );
    use List::AllUtils qw( each_arrayref );
    
    my @x = 1 .. 1_000;
    my @y = map { "$_" } 1 .. 1_000;
    
    my $comp = Array::Compare->new;
    
    cmpthese -5, {
        iterator => sub { my $r = elementwise_eq(\(@x, @y)) },
        array_comp => sub { my $r = $comp->compare(\(@x, @y)) },
    };
    

    This is the worst case scenario where elementwise_eq has to go through each and every element in both arrays 1_000 times and it shows:

                 Rate   iterator array_comp
    iterator    246/s         --       -75%
    array_comp 1002/s       308%         --
    

    On the other hand, the best case scenario is:

    my @x = map { rand } 1 .. 1_000;
    my @y = map { rand } 1 .. 1_000;
    
                  Rate array_comp   iterator
    array_comp   919/s         --       -98%
    iterator   52600/s      5622%         --
    

    iterator performance drops quite quickly, however:

    my @x = 1 .. 20, map { rand } 1 .. 1_000;
    my @y = 1 .. 20, map { rand } 1 .. 1_000;
    
                  Rate   iterator array_comp
    iterator   10014/s         --       -23%
    array_comp 13071/s        31%         --
    

    I did not look at memory utilization.

提交回复
热议问题