【问题标题】:Perl Compare hash of arrays with another arrayPerl 将数组的哈希值与另一个数组进行比较
【发布时间】:2016-08-06 13:35:56
【问题描述】:

我正在尝试将所有数组值(完整数组)与哈希值(数组)进行比较,如果找到匹配项,则将哈希键推送到新数组。 下面的代码比较哈希值是否不是数组,但如果是数组,我该如何比较?

%hash=(
       storeA=>['milk','eggs'],
       storeB=>['milk','fruits','eggs','vegetables'],
       storeC=>['milk','fruits','eggs'],
      );

@array = (
        'fruits',
        'milk',
        'eggs'
    );

要比较的代码

use strict;
use warnings;
use Data::Dumper;

foreach my $thing (@array)   {
     foreach ((my $key, my $value) = each %hash)   { 
                 if ($value eq $thing)   {
                       push @new_array, $key;
                }
          }
   }
  print Dumper(\@new_array);

预期输出

@new_array = (
               storeB,
               storeC
       );

【问题讨论】:

    标签: arrays perl hash hashmap compare


    【解决方案1】:

    求两个集合的交集,如果它的元素个数是数组元素个数,你要存key:

    #!/usr/bin/perl
    use warnings;
    use strict;
    
    
    sub intersect {
        my ($arr1, $arr2) = @_;
        my %intersection;
        $intersection{$_}{0}++ for @$arr1;
        $intersection{$_}{1}++ for @$arr2;
        return grep 2 == keys %{ $intersection{$_} }, keys %intersection
    }
    
    
    my %hash = (
                storeA => [qw[ milk eggs ]],
                storeB => [qw[ milk fruits eggs vegetables ]],
                storeC => [qw[ milk fruits eggs ]],
               );
    
    my @array = qw( fruits milk eggs );
    
    my @new_array;
    
    while (my ($store, $arr) = each %hash) {  # while, not for!
        push @new_array, $store if @array == intersect(\@array, $arr);
    }
    
    use Data::Dumper;
    print Dumper(\@new_array);
    

    【讨论】:

      【解决方案2】:

      您还可以使用allany 的组合形式List::Util

      while ((my $key, my $value) = each %hash) {
          if ( all { my $temp = $_; any { $_ eq $temp } @$value } @array ) {  
              push @new_array, $key;
          }
      }
      

      因此,您在这里寻找@array 的所有元素都存在于哈希中的给定数组中的情况。

      【讨论】:

        【解决方案3】:

        遍历所有存储(键)并为每个检查是否所有数组元素都在键的数组引用中。

        use strict;
        use warnings;
        
        my %inventory = (
            storeA => ['milk','eggs'],
            storeB => ['milk','fruits','eggs','vegetables'],
            storeC => ['milk','fruits','eggs'],
        );    
        my @items = ('fruits', 'milk', 'eggs');
        
        my @found;
        foreach my $store (keys %inventory) {
            push @found, $store 
                if @items == grep { in_store($_, $inventory{$store}) } @items
        }   
        
        sub in_store { for (@{$_[1]}) { return 1 if $_[0] eq $_ }; return 0; }
        
        print "@found\n";  # prints:  storeB storeC
        

        grep 块检查每个项目是否(可用)在存储中,以及通过的数量是否等于存储的所有项目并被添加的项目数(数组大小)。请注意,子例程返回最后评估的值而没有显式返回,因此不需要最终的return。为了清楚起见,添加了它。

        【讨论】:

        • 或者,sub in_store { $_[0] eq $_ and return 1 for @{$_[1]} }
        【解决方案4】:

        试试这个。我在这里做了一个小技巧。 grep 用于过滤数组中的元素。

        我创建了变量$joined_array,其中包含| 分隔的@array 数据。然后我将变量传递给 grep。

        诀窍是,当数组与标量数据进行比较时,比较行为是数组元素与标量数据的总数。

        my @array = qw(one two three);
        
        if(@array == 3)
        {
            print "Hi\n";
        
        }
        

        这里的条件在内部运行为3 == 3

        我在这里做的同样的逻辑。

        use warnings;
        use strict;
        my %hash=(
            "storeA"=>['milk','eggs'],
            "storeB"=>['milk','fruits','eggs','vegetables'],
            "storeC"=>['milk','fruits','eggs'],
        );
        
        my @array = (
            'fruits',
            'milk',
            'eggs'
        );
        
        my @new_array;
        
        my $joined_array = join("|",@array);
        
        foreach (keys  %hash)
        {
        
         push(@new_array,$_) if  ((grep{ /\b$joined_array\b/ } @{$hash{$_}}) >= scalar @array);
        
        }
        
        print "$_\n" for @new_array
        

        【讨论】:

        • 一个好主意,但如果storeC 库存eggshells 那么它将满足列表中的eggs。最好使用@array 而不是3,因为它既表达了意义,又表达了价值,并且如果@array 的内容发生变化,它也能继续工作。我想知道您为什么选择将常数放在比较的首位?这一点都没有错,但是使用3 <= $expression 而不是$expression >= 3 是非常少见的。
        • 哦,我不会去改变像$,这样的内置变量的值,尤其是没有将相关代码包装在一个块中并使用local。没有人记得他们做了什么,print "$_\n" for @new_array 在这里很好
        • @Borodin 感谢您编辑了有用的评论帖子。我使用 word bountry \b 进行匹配。然后>= 3 的原因是数组值的某个时间散列包含重复数据,例如`storeB=>['milk','fruits','eggs','vegetables','milk]` 我的条件将满足,@ 987654341@ 不满足上述数据。 :)。
        • 我不清楚您使用>= 的原因。 grep 将始终返回数组中元素的数量,如果它们都匹配,则不管是否重复。 perl -E 'say scalar grep /a/, qw/ a a a a/' 打印 4
        • @Borodin 考虑例如storeB=>['milk','fruits','eggs','vegetables','milk] 现在grep 结果值4。如果3==4 表示不满意。所以我把>=.
        【解决方案5】:

        我将从每个商店的库存数组中构建一个散列。这是一种浪费的方法,但只要真实数据不是很大,就不会太严重

        像这样。内部 grep 语句计算 @list 中该商店可用的商品数量,并将其与列表中的商品数量进行比较,如果所有商品都有库存,则返回 true

        如果这是真实情况(我怀疑这是家庭作业),那么出于我能想到的所有实际目的,%stocks 哈希应该包含 哈希 每家商店可用的商品 p>

        use strict;
        use warnings 'all';
        
        my %stocks = (
            storeA => [ qw/ milk eggs / ],
            storeB => [ qw/ milk fruits eggs vegetables / ],
            storeC => [ qw/ milk fruits eggs / ],
        );
        
        my @list = qw/ fruits milk eggs /;
        
        my @stores = grep {
            my %stock = map { $_ => 1 } @{ $stocks{$_} };
            grep($stock{$_}, @list) == @list;
        } keys %stocks;
        
        use Data::Dump;
        dd \@stores;
        

        输出

        ["storeB", "storeC"]
        

        【讨论】:

          猜你喜欢
          • 2012-08-21
          • 1970-01-01
          • 1970-01-01
          • 2015-05-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-03
          相关资源
          最近更新 更多