首页 > 解决方案 > 如何在perl中忽略哈希的键序列

问题描述

我有一个包含如下信息的文件

1:2=14
3:4=15
2:1=16
4:3=17

我想创建一个哈希处理密钥{1:2}与密钥相同{2:1}

$hash{1:2} = $hash{2:1}

因此,当我打印所有元素时,$hash{1:2}或者$hash{2:1}它给了我两者1416作为结果。这是一种简单的方法吗?

以下是我计划为哈希创建密钥

for ( my $i = 0; $i <=$#file ; $i++) {
    my $line = $file[$i];
    my @key = split ("=",$line);
    my $hash{$key[0]} = $key[1];
}

标签: perlhashkey

解决方案


没有内置的方法可以做到这一点。如果您的键遵循相同的模式,您可以将其包装在一个函数中,然后计算适合您的算法的所有键并获取值。

my %hash = (
    '1:2' => 14,
    '3:4' => 15,
    '2:1' => 16,
    '4:3' => 17,
);

sub get_elements {
    my ($key) = @_;

    return $hash{$key}, $hash{reverse $key}; # or $key =~ s/(\d+):(\d+)/$2:$1/r
}

print join ' ', get_elements('1:2');

这使用 string reverse,并且显然仅在密钥的部分只有一位时才有效。如果你可以有大于 9 的数字,你将不得不拆分字符串并重新组合它,或者使用替换来切换它们。我的示例使用了/r修饰符,它需要Perl 5.14 或更高版本


但是,如果您想在读取自动处理此问题的文件时构建数据结构,您也可以这样做。使用数组引用而不是哈希中的简单值,并将相同的引用分配给您希望相等的所有键。

use strict;
use warnings;
use feature 'say';
use Data::Dumper;

my %hash;
while (my $line = <DATA>) {
    chomp $line;
    my ($key, $value) = split /=/, $line;
    my ($left, $right) = split /:/, $key;

    # $hash{$key} //= ( $hash{"$right:$left"} // [] ); # needs 5.10
    $hash{$key} = ( $hash{"$right:$left"} || [] )
        unless exists $hash{$key};

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

say "@{ $hash{'1:2'} }";
say "@{ $hash{'2:1'} }";

print Dumper \%hash;

__DATA__
1:2=14
3:4=15
2:1=16
4:3=17

这段代码的输出是

14 16
14 16

Data::Dumper 结构看起来像这样,它解释了键2:11:2指向同一个数组引用。这意味着,如果您将push另一个值放入其中一个,它也会最终出现在另一个中,因为它们实际上是同一件事。

$VAR1 = {
          '4:3' => [
                     '15',
                     '17'
                   ],
          '3:4' => $VAR1->{'4:3'},
          '2:1' => [
                     '14',
                     '16'
                   ],
          '1:2' => $VAR1->{'2:1'}
        };

唯一的缺点是您无法恢复元素的顺序。这种数据结构失去了最初1:2具有价值14的知识。如果你想输出这将不起作用。2:1162:116 14


推荐阅读