Perl array hash print - arrays

I'm a novice. I've got this..
%categories = (
'Announcements' => ['Auctions', 'Bands-Seeking-Members', 'Boutiques', 'Charity'],
'Appliances' => ['Dishwashers', 'Fireplaces/Wood-Burning-Stoves', 'Microwaves'],
'Auto-Parts-and-Accessories' => ['Auto-Accessories', 'Car-Audio-and-Video],
'Baby' => ['Baby-Clothing', 'Backpacks-and-Carriers', 'Changing', 'Cribs-and-Playpens'],
'Books-and-Media' => ['Blu-ray-Discs', 'Books:-Children'],
'Clothing-and-Apparel' => ['Boys-Clothing', 'Boys-Shoes', 'Costumes']
);
I need it to print this..
• Announcements
-Auctions
-Bands-Seeking-Members
-Boutiques
-Charity
•Appliances etc
This is the code so far..
while( my ($cat,$subcat) = each %categories) {
print qq~• $cat
~;
print qq~- $subcat
~;
}
It's printing this..
• Clothing-and-Apparel
- ARRAY(0x1e959c0)
• Announcements
- ARRAY(0x1e95590)
• Auto-Parts-and-Accessories
- ARRAY(0x1e95740)

I believe the following should do what you want:
while(my ($cat, $subcats) = each %categories) {
print "• $cat\n";
foreach my $subcat (#$subcats) {
print "- $subcat\n";
}
}
I have added a for loop to iterate over the contents of your subcategory arrays.
If you need the categories and subcategories sorted alphabetically, try this:
foreach my $cat (sort keys %categories) {
print "• $cat\n";
my $subcategories = $categories{$cat};
foreach my $subcat (sort #$subcategories) {
print "- $subcat\n";
}
}

Related

Get array object data from exploded array fields in foreach loop

I'm trying to extract data from our JSON data based on given output fields, but I'm not getting a good result.
e.g.
Given fields that I want:
Array
(
[0] => id
[1] => name
[2] => email
[3] => optin_email
)
Those fields exist in my datastring, I want to export those to a CSV.
I can do this, hardcoded
foreach ($jsonString as $value) {
$row = [
$value->id,
$value->name,
$value->email,
$value->phone
];
print_r($row);
}
The above will give me the list/file I need. BUT, I want to make that dynamic based on the data in the array, so, fo rexample, when this is the Array:
Array
(
[0] => id
[1] => name
)
This should be my output:
foreach ($jsonString as $value) {
$row = [
$value->id,
$value->name
];
print_r($row);
}
So I need to dynamicly create the
$value->{var}
I have been trying forever, but I am not seeing it straight anymore.
Tried this:
$rowFields = '';
foreach ($export_datafields AS $v) {
$rowFields .= '$value->' . $v . ',';
}
$trimmed_row_fields = rtrim($rowFields, ',');
foreach ($jsonString as $value) {
$row = $trimmed_row_fields;
print_r($row);
}
And several variations of that:
foreach ($jsonString as $value) {
$row = [$trimmed_row_fields];
print_r($row);
}
Question is: how can I get
$value->VAR
as a valid array key when I only know the VAR name and need the prefixed $value-> object.
I ended up using the following code which works for me. If anybody still has the answer to my original question, please shoot. Always good to know it all.
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=$csvFileName");
header("Pragma: no-cache");
header("Expires: 0");
$new_row = implode(",", $export_datafields) . "\n";
foreach ($jsonString as $value) {
foreach ($export_datafields AS $v) {
$new_row .= $value->$v . ',';
}
$new_row = substr($new_row, 0, -1);
$new_row .= "\n";
}
echo $new_row;

How to replace a value in an array's element with another element from the same array?

I have an element in an array, called $row[0], that contains this absolute pathname:
/home/<username>/puppet/config/files/$HOSTGROUP/$TOOLNAME/$VERSION
I'd like to replace each of the three variables listed in that path with three matching elements that are part of the same array...
$row[3] (represents $HOSTGROUP)
$row[4] (represents $TOOLNAME)
$row[5] (represents $VERSION)
How can I do this in a Perl script?
my %repl = (
HOSTGROUP => $row[3],
TOOLNAME => $row[4],
VERSION => $row[5],
);
my $pat = join '|', map quotemeta, keys %repl;
my $re = qr/\$($pat)\b/;
$row[0] =~ s/$re/$repl{$1}/g;
or
my %repl = (
HOSTGROUP => $row[3],
TOOLNAME => $row[4],
VERSION => $row[5],
);
$row[0] =~ s{(\$(\w+))}{
if (exists($repl{$2})) {
$repl{$2}
} else {
warn("Unrecognized var $2\n");
$1
}
}eg;

SilverStripe 3.1 loop associative array

In SilverStripe 3.1 I have a function that loops through an array and outputs its contents.
The output it gives me is:
Layout: John
Strategy: John
Management: Martin
In this example John has more than one job.
I would like to group the jobs if a person has more than one job.
This is my desired Output:
Layout and Strategy: John
Management: Martin
//$InfoFieldArray = array('Layout' => 'John', 'Strategy' => 'John', 'Management' => 'Martin');
public function createInfoFields($InfoFieldArray){
$Info = ArrayList::create();
foreach($InfoFieldArray as $key => $value ){
$fields = new ArrayData(array('FieldName' => $key, 'Value' => $value));
$Info->push($fields);
}
return $Info;
}
How do I alter my function to achieve my desired output?
One possible solution to that is by restructuring the data before adding it to the ArrayList.
public function createInfoFields($InfoFieldArray)
{
$info = array();
foreach ($InfoFieldArray as $job => $person)
{
if (!isset($info[$person]))
{
$info[$person] = array();
}
$info[$person][] = $job;
}
$result = ArrayList::create();
foreach ($info as $person => $jobs)
{
$fields = new ArrayData(array('FieldName' => implode(' and ', $jobs), 'Value' => $person));
$result->push($fields);
}
return $result;
}
What I have done is go over the array of jobs and the person assigned and flipped it the other way around, so I have an array of people with a list of jobs. This allows me to then just call implode in PHP, joining the various jobs by the word and.
There are some potential drawbacks, if there are two people named "John", they will be treated as one as I am using the name as the array key.
Also, if there are three jobs for a person, it will list it like "Layout and Strategy and Management". To avoid that, we need to modify the second foreach loop in my code to something like this:
foreach ($info as $person => $jobs)
{
$jobString = null;
if (count($jobs) > 1)
{
$jobString = implode(', ', array_slice($jobs, 0, -1)) . ' and ' . array_pop($jobs);
}
else
{
$jobString = $jobs[0];
}
$fields = new ArrayData(array('FieldName' => $jobString, 'Value' => $person));
$result->push($fields);
}
When there is more than 1 job for a person, we want to implode (glue together) the array pieces for the $jobs array however we don't want the last element at this point. Once array is glued together, we append with with and along with the last item.

Perl: Comparing 2 hash of arrays with another array

I have written the code below in Perl but it's not giving the desirable output. I am dealing with the comparison between one array and two hash of arrays.
Given sample input files:
1) file1.txt
A6416 A2318
A84665 A88
2) hashone.pl
%hash1=(
A6416=>['E65559', 'C11162.1', 'c002gnj.3',],
A88=>['E77522', 'M001103', 'C1613.1', 'c001hyf.2',],
A84665=>['E138347', 'M032578', 'C7275.1', 'c009xpt.3',],
A2318=>['E128591', 'C43644.1', 'C47705.1', 'c003vnz.4',],
);
3) hashtwo.pl
%hash2=(
15580=>['C7275.1', 'E138347', 'M032578', 'c001jnm.3', 'c009xpt.2'],
3178=>['C1613.1', 'E77522','M001103', 'c001hyf.2', 'c001hyg.2'],
24406=>['C11162.1', 'E65559', 'M003010', 'c002gnj.2'],
12352=>['C43644.1', 'C47705.1', 'E128591','M001458', 'c003vnz.3'],
);
My aim is to achieve the task described:
From file1.txt, I have to locate the corresponding ID in %hash1. For instance,A6416 (file1.txt) is the key in %hash1. Next, I have to find the values of A6416 ['E65559', 'C11162.1', 'c002gnj.3',] in %hash2. If majority (more than 50%) of the values are found in %hash2, I replace A6416 with corresponding key from %hash2.
Example:
A6416 A2318
A84665 A88
Output:
24406 12352
15580 3178
Please note that the keys for %hash1 and %hash2 are different (they don't overlap). But the values are the same (they overlap).
#!/usr/bin/perl -w
use strict;
use warnings;
open FH, "file1.txt" || die "Error\n";
my %hash1 = do 'hashone.pl';
my %hash2 = do 'hashtwo.pl';
chomp(my #array=<FH>);
foreach my $amp (#array)
{
if ($amp =~ /(\d+)(\s?)/)
{
if (exists ($hash1{$1}))
{
for my $key (keys %hash2)
{
for my $i ( 0 .. $#{ $hash2{$key} } )
{
if ((#{$hash1{$1}}) eq ($hash2{$key}[$i]))
{
print "$key";
}
}
}
}
}
}
close FH;
1;
Any guidance on this problem is highly appreciated. Thank you!
I think you should invert %hash2 into this structure:
$hash2{'C7275.1'} = $hash2{'E138347'} = $hash2{'M032578'}
= $hash2{'c001jnm.3'} = $hash2{'c009xpt.2'} = 15580;
$hash2{'C1613.1'} = $hash2{'E77522'} = $hash2{'M001103'}
= $hash2{'c001hyf.2'} = $hash2{'c001hyg.2'} = 3178;
$hash2{'C11162.1'} = $hash2{'E65559'}
= $hash2{'M003010'} = $hash2{'c002gnj.2'} = 24406;
$hash2{'C43644.1'} = $hash2{'C47705.1'} = $hash2{'E128591'}
= $hash2{'M001458'} = $hash2{'c003vnz.3'} = 3178;
So that you can perform these look-ups much more effectively, rather than having to iterate over every element of every element of %hash2.
Building on the responses from ruakh and zock here is the code you need to build the look-up table for hash2
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %hash2=(
15580=>['C7275.1', 'E138347', 'M032578', 'c001jnm.3', 'c009xpt.2'],
3178=>['C1613.1', 'E77522','M001103', 'c001hyf.2', 'c001hyg.2'],
24406=>['C11162.1', 'E65559', 'M003010', 'c002gnj.2'],
12352=>['C43644.1', 'C47705.1', 'E128591','M001458', 'c003vnz.3'],
);
# Build LUT for hash2
my %hash2_lut;
foreach my $key (keys %hash2)
{
foreach my $val (#{$hash2{$key}})
{
$hash2_lut{$val} = $key
}
}
print Dumper(\%hash2_lut);
Please select ruakh's post as the answer, just trying to clarify the code for you. Use Data::Dumper...it is your friend.
Here is the output:
$VAR1 = {
'C47705.1' => '12352',
'M032578' => '15580',
'E138347' => '15580',
'E77522' => '3178',
'C7275.1' => '15580',
'c001jnm.3' => '15580',
'E65559' => '24406',
'C1613.1' => '3178',
'M001458' => '12352',
'c002gnj.2' => '24406',
'c009xpt.2' => '15580',
'c001hyf.2' => '3178',
'C43644.1' => '12352',
'E128591' => '12352',
'c001hyg.2' => '3178',
'M003010' => '24406',
'c003vnz.3' => '12352',
'C11162.1' => '24406',
'M001103' => '3178'
};

Perl CGI scrolling list wont print array of Hash

I am trying to write a Perl CGI script that prints /etc/passwd users but when I open my CGI my scrolling list just prints out multiple lines of this:
"HASH(0x27836d8)"
Here is my code where I grab etc passwd and print it to the scrolling list. Can anyone help me out with printing this correctly to the scrolling list?
setpwent();
while (#list = getpwent())
{
($LOGIN,$PASSWORD,$UID,$GID,$QUOTA,$COMMENT,$GECOS,$HOMEDIR,$SHELL) = #list[0,1,2,3,4,5,6,7,8];
if( $UID >= 1001 )
{
push #users, { login => "$LOGIN"};
}
}
endpwent();
print scrolling_list(-name=>'user_list',
-values=>[#users],
-size=>15);
You gave the list a bunch of hash references, so that's what got displayed. Change
push #users, { login => "$LOGIN"};
to
push #users, $LOGIN;
use strict;
use warnings;
...
setpwent();
while (my #list = getpwent()) {
my ($user, $uid) = #list[2, 3];
push #users, $user
if $ui >= 1001;
}
endpwent();
print scrolling_list(
-name => 'user_list',
-values => \#users,
-size => 15,
);
As documented in the CGI perldoc, the thing you pass with -values should be a list ref, but you've created a list ref to a list of hashes (due to your use of curly braces above). Here's a fixed version:
setpwent();
while (#list = getpwent())
{
($LOGIN,$PASSWORD,$UID,$GID,$QUOTA,$COMMENT,$GECOS,$HOMEDIR,$SHELL) = #list[0,1,2,3,4,5,6,7,8];
if( $UID >= 1001 )
{
push #users, $LOGIN;
}
}
endpwent();
print scrolling_list(-name=>'user_list',
-values=>\#users,
-size=>15);

Resources