【问题标题】:Perl, checking various types of hash for empty key values, jsonPerl,检查各种类型的散列是否有空键值,json
【发布时间】:2017-09-23 22:44:52
【问题描述】:

我现在正在为我的函数实现某种模拟。我这里有个小问题。根据情况,我可以获得不同类型的 json 以及不同类型的哈希。它可以是具有空键值的简单散列,也可以是具有空值或非空值的散列数组的散列。

my %ch1 = (
    "a" => "",
    "b" => "",
    "c" => ""
);

my %ch2 = (
    "tab" => [
        {   
            "a" => 11,
            "b" => 22,
            "c" => 33
        },
        {
            "a" => 44,
            "b" => 55,
            "c" => 66
        }
    ]
);

我需要创建一个函数来检查这两种类型的哈希,计算空值并与哈希键的数量进行比较。

这有点适用于第一个哈希,但我不知道如何使它适用于两个哈希而无需硬编码。

my $tck = 0;
for (keys %ch1){
    if ($ch1{$_} eq ""){
        print "'$ch1{$_}'\n";
        $tck++;
    }
}
if ($tck == scalar keys %ch1){
    # do something
}

有什么建议吗?

【问题讨论】:

  • 第二种的结构总是这样吗?您是要检查该结构中的每个散列,包括顶层,还是只检查数组 ref 中的散列?
  • 用一个函数处理不同类型的数据似乎很奇怪。但是,在不了解更多上下文的情况下,很难给出适当的建议。规范化数据结构是正确的答案吗?或者,编写不同的函数来处理不同的数据结构更好吗?只有更好地了解围绕这个问题的背景,才能给出这些问题和类似问题的答案。
  • 将近 100 个字要说“我不知道”?

标签: json perl hash


【解决方案1】:

您可以使用Data::Visitor::Callback 来执行此操作。这是一个非常简单的实现,只要您的数据结构中没有其他包含空字符串的东西。

模块访问数据结构中的每个项目并在这些项目上调用用户定义的回调。它会对每个 ref 和这些 ref 中的每个值执行此操作。

use strict;
use warnings;
use Data::Visitor::Callback;

my %ch1 = (
    "a" => "",
    "b" => "",
    "c" => ""
);

my $empty_strings;
my $v = Data::Visitor::Callback->new(
    value => sub {
        ++$empty_strings if $_ eq q{}; # q{} is like '' but easier to read
    },
);

$v->visit( \%ch1 );
print $empty_strings;

这将输出3,因为输入哈希中有三个空字符串。请注意,它需要一个哈希引用,而不是哈希本身。

您也可以传入更复杂的数据结构。布局并不重要。我在您的第二个示例中添加了一个空字符串以表明它有效。

use strict;
use warnings;
use Data::Visitor::Callback;

my $empty_strings;
my $v = Data::Visitor::Callback->new(
    value => sub {
        ++$empty_strings if $_ eq q{};
    },
);

my %ch2 = (
    "tab" => [
        {
            "a" => 11,
            "b" => 22,
            "c" => 33
        },
        {
            "a" => '',
            "b" => 55,
            "c" => 66
        }
    ]
);

$v->visit( \%ch2 );
print $empty_strings;

在这种情况下,输出为1

因为没有简单的方法来区分它查看的值是键还是值,因此以下内容也将被此实现计算在内。所以它并不完美,但应该适用于您显示的数据类型。

my %fail = (
    ""  => "foo",        # one
    "b" => [ "", "" ],   # two, three
);

此数据结构将产生$empty_strings 计数3

【讨论】:

    【解决方案2】:

    我不确定我是否正确理解了这个问题,但假设这是您的程序需要能够处理的仅有的两种数据结构,这里有一种处理它们的方法:

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    use List::MoreUtils qw( all none );
    
    my %ch1 = (
        "a" => "",
        "b" => "",
        "c" => ""
    );
    
    my %ch2 = (
        "tab" => [
            {
                "a" => 11,
                "b" => 22,
                "c" => 33
            },
            {
                "a" => 44,
                "b" => 55,
                "c" => 66
            }
        ]
    );
    
    use YAML::XS;
    for my $h ( \(%ch1, %ch2) ) {
        print Dump n_keys_empty_values( $h );
    }
    
    sub n_keys_empty_values {
        my $h = shift;
    
        if ( all { ref } values %$h ) {
            return [ map { my $v = $_; map count_empty_values( $_ ), @$v } values %$h ]
        }
        elsif ( none { ref } values %$h ){
            return [ count_empty_values( $h ) ];
        }
        else {
            die "Unexpected data structure\n";
        }
    }
    
    sub count_empty_values {
        my $h = shift;
        [ scalar keys %$h, scalar grep $_ eq '', values %$h ];
    }
    

    输出:

    --- - - 3 - 3 --- - - 3 - 0 - - 3 - 0

    n_keys_empty_values 的返回值是对数组引用数组的引用。外部数组的大小对应于传递的内部哈希的数量。 count_empty_values 引用哈希并计算键的数量和空字符串的值的数量。

    【讨论】:

      【解决方案3】:

      以这种方式编写你的函数,它会遍历参数列表。然后,您可以将单个哈希 \%ch1 或哈希列表 @{$ch2{tab}} 传递给函数。

      #! /usr/bin/perl
      use strict;
      use warnings;
      
      my %ch1 = (
          "a" => "",
          "b" => "",
          "c" => ""
      );
      
      my %ch2 = (
          "tab" => [
              {
                  "a" => 11,
                  "b" => 22,
                  "c" => 33
              },
              {
                  "a" => 44,
                  "b" => 55,
                  "c" => 66
              }
          ]
      );
      
      my %ch3 = (
          "tab" => [
              {
                  "a" => '',
                  "b" => '',
                  "c" => ''
              },
              {
                  "a" => '',
                  "b" => '',
                  "c" => ''
              }
          ]
      );
      
      sub fun
      {
        for (@_) {
          my %ch = %{$_};
          my $tck = 0;
          for (keys %ch){
            if ($ch{$_} eq ""){
              print "'$ch{$_}'\n";
              $tck++;
            }
          }
          if ($tck == scalar keys %ch){
            print "do something\n";
          }
        }
      }
      
      fun (\%ch1);
      fun (@{$ch2{tab}});
      fun (@{$ch3{tab}});
      

      【讨论】:

        猜你喜欢
        • 2021-04-05
        • 2011-05-24
        • 1970-01-01
        • 1970-01-01
        • 2010-09-24
        • 1970-01-01
        • 1970-01-01
        • 2019-04-05
        相关资源
        最近更新 更多