简体   繁体   English

hash 与散列数组 perl

[英]hash with array of hashes in perl

I know this topic has been covered but other posts usually has static hashes and arrays and the don't show how to load the hashes and arrays.我知道这个主题已经被覆盖,但其他帖子通常有 static 哈希和 arrays 并且不显示如何加载哈希和 arrays。 I am trying to process a music library.我正在尝试处理音乐库。 I have a hash with album name and an array of hashes that contain track no, song title and artist.我有一个带有专辑名称的 hash 和一个包含曲目编号、歌曲标题和艺术家的哈希数组。 This is loaded from an XML file generated by iTunes.这是从 iTunes 生成的 XML 文件加载的。

the pared down code follows:

use strict;
use warnings;
use utf8;
use feature 'unicode_strings';
use feature qw( say );
use XML::LibXML qw( );
use URI::Escape;

my $source = "Library.xml";
binmode STDOUT, ":utf8";

# load the xml doc

my $doc = XML::LibXML->load_xml( location => $source )
    or warn $! ? "Error loading XML file: $source $!"
    : "Exit status $?";

    my %hCompilations;
    my %track;

    # extract xml fields
    my @album_nodes = $doc->findnodes('/plist/dict/dict/dict');
    for my $album_idx (0..$#album_nodes) {
        my $album_node = $album_nodes[$album_idx];
        my $trackName = $album_node->findvalue('key[text()="Name"]/following-sibling::*[position()=1]');
        my $artist = $album_node->findvalue('key[text()="Artist"]/following-sibling::*[position()=1]');
        my $album = $album_node->findvalue('key[text()="Album"]/following-sibling::*[position()=1]');
        my $compilation = $album_node->exists('key[text()="Compilation"]');

        # I only want compilations
        if( ! $compilation ) { next; }

        %track = (
                trackName => $trackName,
                trackArtist => $artist,
                );

        push @{$hCompilations{$album}} , %track;    
    }
#loop through each album access the album name field and get what should be the array of tracks
foreach my $albumName ( sort keys %hCompilations ) {
    print "$albumName\n";
    my @trackRecs = @{$hCompilations{$albumName}};

    # how do I loop through the trackrecs?
}

first of all you want to push the hash as a single element, so instead of首先,您要将 hash 作为单个元素推送,所以而不是

    push @{$hCompilations{$album}} , %track;    

use利用

    push @{$hCompilations{$album}} , {%track};

in the loop you can access the tracks with:在循环中,您可以通过以下方式访问曲目:

foreach my $albumName ( sort keys %hCompilations ) {
    print "$albumName\n";
    my @trackRecs = @{$hCompilations{$albumName}};

    # how do I loop through the trackrecs?
    foreach my $track (@trackRecs) {
       print $track->{trackName} . "/" . $track->{trackArtist} . "\n";
    }
}

This line isn't doing what you think it is:这条线没有做你认为的那样:

push @{$hCompilations{$album}} , %track;

This will unwrap your hash into a list of key/value pairs and will push each of those individually onto your array.这会将您的 hash 解包到键/值对列表中,并将其中的每一个单独推送到您的数组中。 What you want is to push a reference to your hash onto the array.您想要的是将 hash 的引用推送到阵列上。

You could do that by creating a new copy of the hash:您可以通过创建 hash 的新副本来做到这一点:

push @{$hCompilations{$album}} , { %track };

But that takes an unnecessary copy of the hash - which will have an effect on your program's performance.但这需要 hash 的不必要副本 - 这将对您的程序性能产生影响。 A better idea is to move the declaration of that variable ( my %track ) inside the loop (so you get a new variable each time round the loop) and then just push a reference to the hash onto your array.一个更好的主意是将变量的声明( my %track )移动到循环内(这样每次循环都会得到一个新变量),然后只需将对 hash 的引用推送到您的数组中。

push @{$hCompilations{$album}} , \%track;

You already have the code to get the array of tracks, so iterating across that array is simple.您已经有了获取轨道数组的代码,因此遍历该数组很简单。

my @trackRecs = @{$hCompilations{$albumName}};

foreach my $track (@trackRecs) {
   print "$track->{trackName}/$track->{trackArtist}\n";
}

Note that you don't need the intermediate array:请注意,您不需要中间数组:

foreach my $track (@{$hCompilations{$albumName}}) {
   print "$track->{trackName}/$track->{trackArtist}\n";
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM