【问题标题】:Cleaner way to store to replace a scalar hash value with an array ref?用数组 ref 替换标量哈希值的更简洁的存储方式?
【发布时间】:2010-04-08 15:30:16
【问题描述】:

我正在构建一个散列,其中与标量关联的键不一定是唯一的。期望的行为是,如果键是唯一的,则值是标量。如果键不是唯一的,我希望该值是与键关联的标量的数组引用。由于哈希是迭代建立的,我不知道密钥是否是唯一的。现在,我正在做类似的事情

if(!defined($hash{$key})){
   $hash{$key} = $val;
}
elseif(ref($hash{$key}) ne 'ARRAY'){
   my @a;
   push(@a, $hash{$key});
   push(@, $val);
   $hash{$key} = \@a;
}
else{
   push(@{$hash{$key}}, $val);
}

有没有更简单的方法来做到这一点?

【问题讨论】:

  • 从可维护性和简单性的角度来看,假设所有键都不唯一并让每个键成为数组引用不是更容易吗?即使该 arrayref 包含一个元素?转换为更少的if ( ref $x eq 'ARRAY') 样板文件。
  • @rjh 这是一个非常公平的观点。对于我的特定案例,我需要考虑这将如何在更大的图景中发挥作用,但我同意总的来说这是有道理的。它类似于 R 处理事物的方式。这是更复杂结构的一部分,重复键相当少见。我会考虑的。

标签: perl hash


【解决方案1】:

rjh 是正确的。

我已经写了太多的代码,完全按照你的描述——哈希值是一个数组 ref,除非它不是。大量的条件类型检查。然后有一天它打动了我,“我为什么要写这些废话?只要在任何地方都使用数组引用,笨蛋”我对自己说。从那天起,每当我在公园里散步时,蓝鸟就会从树上飞下来给我唱歌。

push @{$hash{$key}}, $val;

这就是你所要做的。如果键不存在,则数组自动激活。

如果您不喜欢 autoviv,并且想要明确说明:

$hash{$key} = [] unless exists $hash{$key};
push @{$hash{$key}}, $val;

即使是这种“冗长”的方法也要短得多。

【讨论】:

  • 只有我一个人能立即想象到怪物史莱克中蓝鸟和菲奥娜唱歌然后鸟爆炸的场景吗? :)
  • 哇,我不知道即使是 arrayref 取消引用也会被自动激活。所以我不再需要@{ $hash{$key} ||= [] } ...整洁!
  • 这是个老问题,但我很好奇为什么要使用 arrayref?为什么不只是 hashref?
  • @vol7ron,如果你想在你的哈希中有多个值,你需要使用一种可以存储多个值的标量。这使您可以使用数组引用、哈希引用或某种序列化方案来管理倍数。根据您使用多个值的方式,使用散列的散列而不是数组的散列可能是有意义的。在这种情况下,OP 询问的是标量或数组的散列。我建议使用一致的结构来节省复杂性。此建议适用于您选择构成数据结构的任何元素。
  • @daotoad:没错,我的意思是我已经完成了 HoA,但 HoH 可能会被滥用以服务于所有目的。我的意思是创建$hash->{$key}->{$index} = 'foo' 来服务于多维数组的相同结构非常容易,其中索引等于$hash->{$key}0 中的键数。如果顺序很重要,只需添加另一个维度 :) 我只是发现 HoHs 非常灵活,但同样,也许我滥用了它。
【解决方案2】:
if(!defined($hash{$key})){
    $hash{$key} = $val;
}
elsif (ref($hash{$key}) ne 'ARRAY') {
    $hash{$key} = [ $hash{$key}, $val ];
}
else{
   push(@{$hash{$key}}, $val);
}

【讨论】:

  • 你真的应该在你的第一个条件中使用exists - undef 可能会出现在$hash{$key} 中,在这种情况下你的最终条件会破坏它。
猜你喜欢
  • 2010-09-29
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2011-12-14
  • 2021-09-21
  • 2019-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多