【问题标题】:How to compare 2 arrays and split in 3 groups?如何比较 2 个数组并分成 3 组?
【发布时间】:2011-03-25 07:17:47
【问题描述】:

假设我有这些数组

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;

我想对它们进行比较,所以我得到了 3 个包含差异的新数组

  • 一个数组,其中的元素位于 @new 中而不是 @old 中:c
  • 包含不在@new@old 中的元素的数组:f
  • 包含@new@old 中元素的数组:a b d e

我正在考虑 exists 函数,但我认为这只适用于哈希。

更新:我搞砸了字母示例。

【问题讨论】:

    标签: arrays perl


    【解决方案1】:

    【讨论】:

    • 这没有给出所需的分组。我明白了。交叉点:a b d e。区别:c f。联合:a b c d e f。
    • 该答案的主要思想是“使用哈希”
    【解决方案2】:

    UPDATE2:正如 Michael Carman 所指出的,如果元素重复,我的算法将失败。所以一个固定的解决方案使用了一个更多的哈希:

    my (%count, %old);
    $count{$_} = 1 for @new;
    $old{$_}++ or $count{$_}-- for @old;
    # %count is now really like diff(1)    
    
    my (@minus, @plus, @intersection);
    foreach (keys %count) {
        push @minus, $_        if $count{$_}  < 0;
        push @plus, $_         if $count{$_}  > 0;
        push @intersection, $_ if $count{$_} == 0;
    };
    

    更新:看起来这个解决方案也涵盖了常见问题解答中的内容:

        push @difference, $_ if $count{$_};
        push @union, $_;
    

    【讨论】:

    • 同意,但常见问题解答中有@union。我提升了您的解决方案——我认为这是一个很好的解决方案,但评论说常见问题解答并没有以同样的方式涵盖
    • 如果数组包含重复的元素,这可能会失败。例如如果“a”在@new 中出现一次,在@old 中出现两次,它的计数将是-1,它会被标记为只存在于@old 而不是两者都存在。
    • 是的。感谢您指出。还 +1 用于提交子代码而不是裸代码。
    【解决方案3】:

    这是我用过很多次的函数。

    sub compute_sets {
        my ($ra, $rb) = @_;
        my (@a, @b, @ab, %a, %b, %seen);
    
        @a{@$ra} = ();
        @b{@$rb} = ();
    
        foreach (keys %a, keys %b) {
            next if $seen{$_}++;
    
            if (exists $a{$_} && exists $b{$_}) {
                push(@ab, $_);
            }
            elsif (exists $a{$_}) {
                push(@a, $_);
            }
            else {
                push(@b, $_);
            }
        }
    
        return(\@a, \@b, \@ab);
    }
    

    它返回对包含第一个/第二个/两个列表中元素的数组的引用:

    my @new = qw/a b c d e/;
    my @old = qw/a b   d e f/;
    
    my ($new_only, $old_only, $both) = compute_sets(\@new, \@old);
    
    say 'new only: ', join ' ', @$new_only; # c
    say 'old only: ', join ' ', @$old_only; # f
    say 'both: ', join ' ', @$both;         # e a b d
    

    【讨论】:

      【解决方案4】:

      【讨论】:

        【解决方案5】:

        List::Compare 处理此类问题。

        #!/usr/bin/perl
        use strict;
        use warnings;
        use List::Compare;
        
        my @new = qw/a b c d e/;
        my @old = qw/a b   d e f/;
        
        my $lc = List::Compare->new(\@new, \@old);
        
        # an array with the elements that are in @new and not in @old : c
        my @Lonly = $lc->get_Lonly;
        print "\@Lonly: @Lonly\n";
        
        # an array with the elements that are not in @new and in @old : f
        my @Ronly = $lc->get_Ronly;
        print "\@Ronly: @Ronly\n";
        
        # an array with the elements that are in both @new and @old : a b d e
        my @intersection = $lc->get_intersection;
        print "\@intersection: @intersection\n";
        
        __END__
        ** prints
        
        @Lonly: c
        @Ronly: f
        @intersection: a b d e
        

        【讨论】:

          【解决方案6】:

          怎么样:

          #!/usr/bin/perl
          use strict;
          use warnings;
          use Data::Dumper;
          
          my @new = qw/a b c d e/;
          my @old = qw/a b   d e f/;
          my %new = map{$_ => 1} @new;
          my %old = map{$_ => 1} @old;
          
          my (@new_not_old, @old_not_new, @new_and_old);
          foreach my $key(@new) {
              if (exists $old{$key}) {
                  push @new_and_old, $key;
              } else {
                  push @new_not_old, $key;
              }
          }
          foreach my $key(@old) {
              if (!exists $new{$key}) {
                  push @old_not_new, $key;
              }
          }
          
          print Dumper\@new_and_old;
          print Dumper\@new_not_old;
          print Dumper\@old_not_new;
          

          输出:

          $VAR1 = [
                    'a',
                    'b',
                    'd',
                    'e'
                  ];
          $VAR1 = [
                    'c'
                  ];
          $VAR1 = [
                    'f'
                  ];
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-07-19
            • 2011-12-01
            • 1970-01-01
            • 2021-11-25
            • 1970-01-01
            • 2020-07-25
            相关资源
            最近更新 更多