简体   繁体   中英

Merge Perl hashes into one array and loop through it

I'm creating a Perl plugin for cPanel which has to get all domains in the account of a user and display it in a HTML select field. Originally, I'm a PHP developer, so I'm having a hard time understanding some of the logic of Perl. I do know that cPanel plugins can also be written in PHP, but for this plugin I'm limited to Perl.

This is how I get the data from cPanel:

my @user_domains = $cpliveapi->uapi('DomainInfo', 'list_domains');
@user_domains = $user_domains[0]{cpanelresult}{result}{data};

This is what it looks like using print Dumper @user_domains :

$VAR1 = {
    'addon_domains' => ['domain1.com', 'domain2.com', 'domain3.com'],
    'parked_domains' => ['parked1.com', 'parked2.com', 'parked3.com'],
    'main_domain' => 'main-domain.com',
    'sub_domains' => ['sub1.main-domain.com', 'sub2.main-domain.com']
};

I want the data to look like this (thanks @simbabque):

@domains = qw(domain1.com domain2.com domain3.com main-domain.com parked1.com parked2.com parked3.com);

So, I want to exclude sub_domains and merge the others in 1 single-dimensional array so I can loop through them with a single loop. I've struggled the past few days with what sounds like an extremely simple task, but I just can't wrap my head around it.

That isn't doing what you think it' doing. {} is the anonymous hash constructor, so you're making a 1 element array, with a hash in it.

You probably want:

use Data::Dumper;

my %user_domains = (
    'addon_domains' => ['domain1.com', 'domain2.com', 'domain3.com'],
    'parked_domains' => ['parked1.com', 'parked2.com', 'parked3.com'],
    'main_domain' => 'main-domain.com',
    'sub_domains' => ['sub1.main-domain.com', 'sub2.main-domain.com'],
);

print Dumper \%user_domains;

And at which point the 'other' array elements you can iterate through either a double loop:

foreach my $key ( keys %user_domains ) { 
    if ( not ref $user_domains{$key} ) { 
        print $user_domains{$key},"\n";
        next;
    }
    foreach my $domain (  @{$user_domains{$key}} ) {
        print $domain,"\n";
    }
}

Or if you really want to 'flatten' your hash:

my @flatten = map { ref $_ : @$_ ? $_ } values %user_domains;
print Dumper \@flatten;

(You need the ref test, because without it, the non-array main-domain won't work properly)

So for the sake of consistency, you might be better off with:

my %user_domains = (
    'addon_domains' => ['domain1.com', 'domain2.com', 'domain3.com'],
    'parked_domains' => ['parked1.com', 'parked2.com', 'parked3.com'],
    'main_domain' => ['main-domain.com'],
    'sub_domains' => ['sub1.main-domain.com', 'sub2.main-domain.com'],
);

You need something like this

If you find you have a copy of List::Util that doesn't include uniq then you can either upgrade the module or use this definition

sub uniq {
    my %seen;
    grep { not $seen{$_}++ } @_;
}

From your dump, the uapi call is returning a reference to a hash . That goes into $cp_response and then drilling down into the structure fetches the data hash reference into $data

delete removes the subdomain information from the hash.

The lists you want are the values of the hash to which $data refers, so I extract those. Those values are references to arrays of strings if there is more than one domain in the list, or simple strings if there is only one

The map converts all the domain names to a single list by dereferencing array references, or passing strings straight through. That is what the ref() ? @$_ : $_ ref() ? @$_ : $_ is doing. FInally uniq removes multiple occurrences of the same name

use List::Util 'uniq';

my $cp_response = $cpliveapi->uapi('DomainInfo', 'list_domains');
my $data        = $cp_response->{cpanelresult}{result}{data};

delete $data->{sub_domains};

my @domains = uniq map { ref() ? @$_ : $_ } values %$data;

output

parked1.com
parked2.com
parked3.com
domain1.com
domain2.com
domain3.com
main-domain.com

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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