在Perl中将数组转换为哈希

4

我有一个源列表,从中随机选取项目并填充目标列表。列表中的项目具有特定的格式。例如:

item1{'name'}
item1{'date'}

等等还有许多其他字段。

在插入到目标列表时,我会检查项目上的唯一名称并将其插入该列表中。为此,我必须遍历整个目标列表以检查是否存在具有给定名称的项目,如果不存在,则插入它。

我认为将目标列表作为哈希表而不是再次作为列表会很好,这样我可以更快速有效地查找项目。我是Perl的新手,不知道如何做到这一点。请问如何在哈希表中插入项目、查找特定项目名称并删除项目?

如何将名称和日期都作为键,整个项目作为值?


你应该阅读perldoc perldscperldoc perldata,其中包含了关于哈希表入门所需的所有信息。 - Ether
4个回答

1

我的%哈希;

  1. 插入一个具有键$K的项目$V?

    $hash{$K} = $V

  2. 查找特定名称/键$K?

    if (exists $hash{$K}) { 
        print "它与值'$hash{$K}'在那里\n";
    } else { 
        print "它不在那里\n" 
    }
  1. 删除特定名称/键?

    delete $hash{$K}

  2. 将名称和日期作为键,整个项目作为值?

简单方法:只需将所有内容串在一起即可

set: $hash{ "$name:$date" } = "$name:$date:$field1:$field2"
get: my ($name2,$date2,$field1,$field2) = split ':', $hash{ "$name:$date" }
del: delete $hash{ "$name:$date" }

更困难的方法:将其存储为哈希中的哈希(搜索“perl对象”)
设置:
my %temp;
$temp{"name"} = $name;
$temp{"date"} = $date;
$temp{"field1"} = $field1;
$temp{"field2"} = $field2

$hash{"$name:$date"} = \$temp;

获取:

my $find = exists $hash{"$name:$date"} ? $hash{"$name:$date"} : undef;
if (defined find) { # i.e. it was found
    printf "field 1 is %s\n", $find->{"field1"}
} else {
    print "Not found\n";
}

删除:
delete $hash{"$name:$date"}

1
如果你的数据中有冒号,那么所谓的“简单方式”可能会变成“困难的方式”。 - user181548
幸运的是,数据中不包含冒号。非常感谢。这个方法可行 :) - Anu
同意,不建议使用简单的方法。你最好使用空字节\0代替冒号,但即使如此也不建议这样做。 - vol7ron

0

由于您没有具体描述输入和期望的输出,因此很难理解您的问题。

我最好的猜测是:

#!/usr/bin/perl

use strict; use warnings;

my @list = (
    q(item1{'name'}),
    q(item1{'date'}),
);

my %lookup;

for my $entry ( @list ) {
    my ($name, $attrib) = $entry =~ /([^{]+){'([^']+)'}/;
    $lookup{ $name }{ $attrib } = $entry;
}

for my $entry ( keys %lookup ) {
    my %entry = %{ $lookup{$entry} };
    print "@entry{keys %entry}\n"
}

use YAML;
print Dump \%lookup;

输出:

item1 {'date'} item1 {'name'}
---
item1:
  date: "item1 {'date'}"
  name: "item1 {'name'}"

0
Perl 解决方案
#!/usr/bin/perl -w

use strict;
use Data::Dumper;

   sub main{
      my %hash;
      my @keys = qw(firstname lastname age);                    # hash's keys
      
      
                  #  fname    lname    age
                  # --------|--------|-----
      my @arr  = ( [ 'foo1',  'bar1',  '1' ],
                   [ 'foo2',  'bar2',  '2' ],
                   [ 'foo3',  'bar3',  '3' ]
                 );
                 
      # test if array set up correctly
      print "\$arr[1][1]       : $arr[1][1] \n";                # bar2      

    
      # loads the multidimensional array into the hash
      for my $row (0..$#arr){
         for my $col ( 0..$#{$arr[$row]} ){
            my $itemnum = "item" . ($row+1);                    # using the item# format you used
            $hash{$itemnum}->{$keys[$col]} = $arr[$row][$col];
         }
      }
      
      # manually add a 4th item
      $hash{item4} = {"firstname", "foo", "lastname", "bar", "age", "35"};
      
      
      
      # How to Retrieve
      # -----------------------
      
      # single item pull
      print "item1->firstname : $hash{item1}->{firstname} \n";  # foo1
      print "item3->age       : $hash{item3}->{age}       \n";  # 3

      # whole line 1
      {  local $, = " "; 
         print "full line        :" , %{$hash{item2}} , "\n";   # firstname foo2 lastname bar2 age 2 
      } 
      
      # whole line 2
      foreach my $key (sort keys %{$hash{item2}}){
         print "$key   : $hash{item2}{$key} \n";
      }
      
      
      # Clearer description
      #print "Hash:\n", Dumper %hash;
   }
   
   main();

这应该是作为已接受答案的补充使用。你的问题在“数组转哈希”要求方面有点含糊,也许这就是你正在寻找的模型?


0

如果你知道需要哪些项,以及它们在键中的顺序,那么重新解析键的价值是有问题的。我更喜欢按级别存储。

$hash{ $h->{name} }{ $h->{date} } = $h;
# ... OR ...
$hash{ $h->{date} }{ $h->{name} } = $h;

foreach my $name ( sort keys %hash ) { 
    my $name_hash = $hash{$name};
    foreach my $date ( keys %$name_hash ) { 
        print "\$hash{$name}{$date} => " . Dumper( $name_hash->{$date} ) . "\n";
    }
}

对于任意层级,您可能需要一个遍历函数

sub traverse_hash (&@) { 
    my ( $block, $hash_ref, $path ) = @_;
    $path = [] unless $path;
    my ( @res, @results );
    my $want           = wantarray;
    my $want_something = defined $want;

    foreach my $key ( %$hash_ref ) { 
        my $l_path = [ @$path, $key ];
        my $value  = $hash_ref->{$key};
        if ( ref( $value ) eq 'HASH' ) { 
            @res = traverse_hash( $block, $value, $l_path );
            push @results, @res if $want_something && @res;
        }
        elsif ( $want_something ) {
            @res = $block->( $l_path, $value );
            push @results, @res if @res;
        }
        else { 
            $block->( $path, $value );
        }
    }
    return unless $want_something;
    return $want ? @results : { @results };
}

所以这个与上面的代码做的事情是一样的:

traverse_hash {
    my ( $key_path, $value ) = @_;
    print( '$hash{' . join( '}{', @$key_path ) . '} => ' . ref Dumper( $value ));
    ();
} \%hash
;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接