【问题标题】:How do you remove undefined keys from a hash?如何从哈希中删除未定义的键?
【发布时间】:2011-12-01 19:51:26
【问题描述】:

尝试使用 map 和 grep 来解决这个问题,知道有什么问题吗?我不断得到一个 Can't use string ("10") as a HASH ref while "strict refs" 当我尝试打印新哈希的值时出错

sub scrub_hash{
    my($self,$hash_ref) = @_;
    my $scrubbed_hash = map { defined $hash_ref->{$_} ? ($_ => $hash_ref->{$_}) : () } keys %{$hash_ref};   
    print STDERR "[scrub]". $_."\n"  for values %{$scrubbed_hash};
}   

在这里使用 ...

my $params_hash = $cgi->Vars();
my $scrubbed = $self->scrub_empty_params($params_hash) if $self->is_hash($params_hash);

在这种情况下,当通过 post 提交表单时未定义的参数仍显示为 key1=&key2= 所以scrub 将它们关闭

【问题讨论】:

  • 还有:delete @hash{ grep !defined($hash{$_}), keys %hash };

标签: perl hash map key


【解决方案1】:

在这一行:

my $scrubbed_hash = map { defined $hash_ref->{$_} ? ($_ => $hash_ref->{$_}) : () } keys %{$hash_ref};   

您正在将来自map 的列表分配给标量$scrubbed_hashmap 在标量上下文中将返回列表中的元素数 (10)。

与其分配给标量,不如分配给复数散列:

sub scrub_hash{
    my($self,$hash_ref) = @_;
    my %scrubbed_hash = map { defined $hash_ref->{$_} ? ($_ => $hash_ref->{$_}) : () } keys %{$hash_ref};   
    print STDERR "[scrub]". $_."\n"  for values %scrubbed_hash;
}   

如果您真的想为$scrubbed_hash 使用标量,则需要用{map {...} args} 包装map 语句,这将从列表中构造一个匿名散列。

要过滤掉元素,你可以使用delete函数:

my %hash = (foo => 1, bar => undef, baz => 2);

defined $hash{$_} or delete $hash{$_} for keys %hash;

print join ', ' => keys %hash;  # foo, baz

根据更新:

scrub_empty_params 方法应如下所示:

sub scrub_empty_params {
    my ($self, $hash) = @_;
    {map {defined $$hash{$_} ? ($_ => $$hash{$_}) : ()} keys %$hash}
}

如果这对您不起作用,那么可能是您的值已定义,但长度为 0。

sub scrub_empty_params {
    my ($self, $hash) = @_;
    {map {(defined $$hash{$_} and length $$hash{$_}) ? ($_ => $$hash{$_}) : ()} keys %$hash}
}

您可能希望通过创建一个返回过滤哈希的不同 ->Vars() 方法从 API 中删除一些样板:

sub clean_vars {
    my ($self) = @_;
    $self->scrub_empty_params($self->Vars)
}

【讨论】:

  • 键 %hash 的部分——这只是一个聪明的 for 循环——是 map 只是另一种编写 for 循环的方法,还是做同样事情的更快方法?
  • for/foreach 和 map 非常相似。最大的区别是如果您尝试使用循环构建列表。如果是这样,my @list = map {...} @srcmy @list; push @list, ... for @src 更短更清晰。如果您只使用循环方面,使用forforeach 可以更清楚地说明您的意图,并且会更快一些。
  • 特别是,foreach 构造理解 1 .. 10000 是一个范围,并且不会在循环开始之前创建所有数字。而map {...} 1 .. 10000 必须在开始循环之前构建范围内的所有数字。换句话说,for/foreachmap 有更多优化案例。
  • 感谢您澄清前一个示例不起作用,当我返回 %scrubbed_hash 时,它仍然包含所有键 =/
  • 我的示例中的代码使用哈希而不是引用,但您的评论显示了对引用用法的正确转换。另一种流行的方式是defined $$hash_ref{$_} or delete $$hash_ref{$_} for keys %$hash_ref,这就是我写它的方式。
【解决方案2】:

试试这个:

    my %scrubbed_hash = map { $_ => $hash_ref->{ $_ } } grep { defined $hash_ref->{$_} } keys %{$hash_ref};   

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 1970-01-01
    • 2013-10-09
    • 1970-01-01
    • 2015-03-16
    • 2023-04-09
    相关资源
    最近更新 更多