Reputation: 453
I'm implementing right now some kind of mock for my function. And i have a little problem here. Depending on situation, i could get different kind of json as well as a different kind of hash of it. It can be a simple hash with empty values of keys or hash of array of hashes with empty or not empty values.
my %ch1 = (
"a" => "",
"b" => "",
"c" => ""
);
my %ch2 = (
"tab" => [
{
"a" => 11,
"b" => 22,
"c" => 33
},
{
"a" => 44,
"b" => 55,
"c" => 66
}
]
);
I need to make a function that checks both types of hash, counts empty values and compares with ammount of keys of hash.
This one kinda works for the first hash, but i don't know how to make it work for both hashes without hardcoding.
my $tck = 0;
for (keys %ch1){
if ($ch1{$_} eq ""){
print "'$ch1{$_}'\n";
$tck++;
}
}
if ($tck == scalar keys %ch1){
# do something
}
Any suggestions?
Upvotes: 2
Views: 883
Reputation: 23824
Write your function in that way, that it iterates over the argument list. Then you can pass either a single hash \%ch1
or a list of hashes @{$ch2{tab}}
to the function.
#! /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}});
Upvotes: 0
Reputation: 118128
I am not confident that I understand the problem correctly, but assuming those are the only two types of data structures your program needs to be able to handle, here is one way of doing something with them:
#!/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 ];
}
Output:
--- - - 3 - 3 --- - - 3 - 0 - - 3 - 0
The return value of n_keys_empty_values
is a reference to an array of array references. The size of the outer array corresponds to the number of inner hashes passed. count_empty_values
takes a reference to a hash and counts the number of keys and number of values which are empty strings.
Upvotes: 0
Reputation: 54323
You could use Data::Visitor::Callback to do that. It's a pretty straight-forward implementation, as long as there are no other things that contain empty strings in your data structure.
The module visits each item in a data structure and calls user-defined callbacks on those items. It will do that for every ref and every value in those refs.
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;
This will output 3
, as there are three empty strings in the input hash. Note that it wants a hash reference, not the hash itself.
You can just as well pass in a more complex data structure. The layout does not really matter. I've added an empty string to your second example to show that it works.
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;
In this case, the output is 1
.
Because there is no easy way to distinguish if a value it looks at is a key or a value, the following things would also be counted with this implementation. So it's not perfect, but should work for the type of data you showed.
my %fail = (
"" => "foo", # one
"b" => [ "", "" ], # two, three
);
This data structure would yield a $empty_strings
count of 3
.
Upvotes: 3