Copying Array elements to Hash - perl

I have an array of Hashes with the following structure:
#fields
(
{
"id" => "Name",
"type" => "Text",
"value" = undef,
},
{
"id" => "DOB",
"type" => "Date",
"value" = undef,
},
);
and I have an array with the following elements:
#data = ("John", "10/10/1970");
What wold be the best way to copy the elements of the #data to #fields to get the following without having to iterate and use array indices.
#fields
(
{
"id" => "Name",
"type" => "Text",
"value" = "John",
},
{
"id" => "DOB",
"type" => "Date",
"value" = "10/10/1970",
},
);

A hash slice would have worked if this was within a single hash reference. However, since you have to populate a specific field across multiple hash references, a loop will be needed.
use List::Util 'min';
$fields[$_]->{value} = $data[$_] for 0 .. min( $#fields, $#data );

Perhaps you should make #fields into a hash instead, which would allow you to easily retrieve a field by name.
use warnings;
use strict;
my %fields =
(
Name => {
type => "Text",
value => undef,
},
DOB => {
type => "Date",
value => undef,
},
);
my #data = ("John", "10/10/1970");
$fields{Name}->{value} = $data[0];
$fields{DOB}->{value} = $data[1];
use Data::Dumper;
print Dumper %fields;

Related

How to iterate through an array of hashes inside an object with perl

I am trying to iterate through an array of hashes stored as the '_skills' attribute of a 'Person' object, and having trouble.
test1.pl
my $person = new Person( "Hubert", "Blu",
[
{"name" => "Python", "Weight" => 80, "group","IT SKILLS", "id"=>0002},
{"name" => "Magic", "Weight" => 100, "group", "MISC SKILLS", "id"=>0001},
{"name" => "JavaScript","Weight" => 70, "group"=> "IT SKILLS", "id"=>0004},
{"name" => "Mage","Weight" => 100, "group"=>"JOB TITLE", "id" =>0003},
{"name" => "Assassin", "Weight" => 85, "group"=>"JOB TITLE"}
]
);
and Person.pl
sub new {
my ($class,$first_name,$last_name,#skills) = #_ ;
my $self = {};
$self->{"_first_name"} = $first_name;
$self->{"_last_name"} = $last_name;
#{$self->{"_skills"}} = #skills;
# Print all the values just for clarification.
print "First Name is $self->{_first_name}\n";
print "Last Name is $self->{_last_name}\n";
print "Skills : " . Data::Dumper::Dumper($self->{_skills}) . "\n";
print"---SKILLS---\n";
my $i = 1;
foreach my $skill_set (#{$self->{_skills}}) {
print "skill ".$i .": \n";
$i++;
#print Data::Dumper::Dumper($skill_set) . "\n";
print "$skill_set->{'_first_name'}";
};
bless $self, $class;
return $self;
}
the first dump shows the array and it looks fine. the second dump inside the loop displays the entire array again, and it only loops through once before finishing with the following error
Not a HASH reference at /home/izoom/PerlTrainingGround/LeeR/lib/Person/Person.pm line 26.
Been stuck for hours any help appreciated as always!
You are passing three arguments to new plus the invocant. The last is a reference to an array. That means that #skills ends up with a single element whose value is that reference.
my $person = new Person( "Hubert", "Blu",
[
{"name" => "Python", "Weight" => 80, "group","IT SKILLS", "id"=>0002},
{"name" => "Magic", "Weight" => 100, "group", "MISC SKILLS", "id"=>0001},
{"name" => "JavaScript","Weight" => 70, "group"=> "IT SKILLS", "id"=>0004},
{"name" => "Mage","Weight" => 100, "group"=>"JOB TITLE", "id" =>0003},
{"name" => "Assassin", "Weight" => 85, "group"=>"JOB TITLE"}
]
);
should be
my $person = new Person( "Hubert", "Blu",
{"name" => "Python", "Weight" => 80, "group","IT SKILLS", "id"=>0002},
{"name" => "Magic", "Weight" => 100, "group", "MISC SKILLS", "id"=>0001},
{"name" => "JavaScript","Weight" => 70, "group"=> "IT SKILLS", "id"=>0004},
{"name" => "Mage","Weight" => 100, "group"=>"JOB TITLE", "id" =>0003},
{"name" => "Assassin", "Weight" => 85, "group"=>"JOB TITLE"}
);
or
my ($class,$first_name,$last_name,#skills) = #_ ;
#{$self->{"_skills"}} = #skills; # Useless shallow array copy
# -or-
$self->{"_skills"} = [ #skills ]; # Same[1] but clearer
# -or-
$self->{"_skills"} = \#skills; # No copy of elements
should be
my ($class,$first_name,$last_name,$skills) = #_ ;
#{$self->{"_skills"}} = #$skills; # Shallow array copy
# -or-
$self->{"_skills"} = [ #$skills ]; # Same[1] but clearer
# -or-
$self->{"_skills"} = $skills; # No copy of elements
Since $self->{"_skills"} is undef at this point.

Fetch a value from an array in a MongoDB collection

Below is my MongoDB collection
{
"_id" : ObjectId("5b2a2ee19d332d0118b26dfe"),
"Name" : "Rock",
"Job" : [
{
"Id" : ObjectId("5b2b93c63629d0271ce366ae"),
"JobName" : "abc",
"JobTrack" : [
"123"
]
}
]
}
I want to fetch both ObjectId values
my $cursor = $custColl->find(
{ 'Job.JobName' => "abc", 'Job.JobTrack' => "123" },
{ '_id' => 1, 'Job.Id' => 1 }
);
while ( my $next = $cursor->next ) {
my $CustomerId = "$next->{_id}";
my $JobId = "$next->{'Job.Id'}";
say "$CustomerId => $JobId\n";
}
The result I got from above code as follows
5b2a2ee19d332d0118b26dfe =>
With this code I'm not able to get $JobId.
Assuming the query finds a document, $next is a Perl data structure that resembles your original JSON:
{
'Name' => 'Rock',
'_id' => bless( {
'value' => '5b2a2ee19d332d0118b26dfe'
}, 'MongoDB::OID' ),
'Job' => [
{
'JobName' => 'abc',
'JobTrack' => [
'123'
],
'Id' => bless( {
'value' => '5b2b93c63629d0271ce366ae'
}, 'MongoDB::OID' )
}
]
}
To get the job ID, you need to dereference that structure using Perl syntax, not MongoDB syntax:
my $JobId = "$next->{Job}[0]{Id}";
You need to access a specific element of the Job array. Because there is only one element in your example it must have an index of zero. Accordingly you need
my $JobId = "$next->{'Job.0.Id'}";

Get key's values which are common in two hashes using perl

I want to create a hash which contains key's values which are common in two hashes. In the below code, "test1" is available in two hashes values. Hence get the key value of both hashes, store it in array and create a new hash
use strict;
use warnings;
my #array1 = ( "test1", "test2", "test3" );
my #array2 = ( "test4", "test5", "test6" );
my #array3 = ( "test7", "test8", "test9" );
my %hashids = ( "1" => \#array1, "2" => \#array2, "3" => \#array3 );
my #targetarray1 = ( "test1", "test2", "test99" );
my #targetarray2 = ( "test4", "test6", "test100" );
my #targetarray3 = ( "test7", "test9", "test66" );
my %hashtarget_ids = ( "a" => \#targetarray1, "b" => \#targetarray2, "c" => \#targetarray3 );
my %finalhash;
my $i;
for my $itemarray ( values %hashids ) {
for my $arrayval (#$itemarray) {
for my $temp ( values %hashtarget_ids ) {
for my $temp_text (#$temp) {
if ( $arrayval eq $temp_text ) {
$i++;
my #final_array;
#print $hashtarget_ids[$$temp],"\n"; ##Print key value here as "a"
#print $hashids[$$temp],"\n"; ##Print key value here as "1"
#push #finalarray,$hashtarget_ids[$$temp]; ##Push key value to array
#push #finalarray,$hash_ids[$$temp]; ##Push key value to array
#%finalhash=("$i"=>\#final_array); ##Create hash
}
}
}
}
}
First a note. To create an array as a value of a hash, you can use an anonymous array ref instead of creating a temporary array variable to later to take a references of:
$hash{key} = [ 'an', 'anonymous', 'array', 'ref' ];
Second, to find values that match between two arrays, check out: How do I compute the difference of two arrays? How do I compute the intersection of two arrays?
I'm afraid that your overall goal is a little unclear. If it's just to find element values that match between the two hashes, then all you need is a %seen style hash:
use strict;
use warnings;
my %hashids = (
"1" => [ "test1", "test2", "test3" ],
"2" => [ "test4", "test5", "test6" ],
"3" => [ "test7", "test8", "test9" ]
);
my %hashtarget_ids = (
"a" => [ "test1", "test2", "test99" ],
"b" => [ "test4", "test6", "test100" ],
"c" => [ "test7", "test9", "test66" ]
);
my %seen;
$seen{$_}++ for map {#$_} values %hashids;
my #final_array = sort grep {$seen{$_}} map {#$_} values %hashtarget_ids;
print "#final_array\n";
Outputs:
test1 test2 test4 test6 test7 test9

Perl Newbie - Printing value from array

I am brand new to perl. I am trying to grab a string out of some JSON output. My code below works, but seems like there is a smarter way to do this. Here is a sample of the JSON
$VAR1 = '{
"hasDetailRows" : true,
"reportMetadata" : {
"reportFormat" : "TABULAR",
"detailColumns" : [ "SUBJECT", "COMMENT_CREATED_DATE", "CASE_COMMENT_CREATED_BY" ],
"reportBooleanFilter" : null,
"reportFilters" : [ {
"column" : "CASE_COMMENT_CREATED_BY",
"operator" : "equals",
"value" : "Username"
} ],
"aggregates" : [ "RowCount" ],
"groupingsDown" : [ ],
"groupingsAcross" : [ ],
"developerName" : "My_Comments",
"reportType" : {
"type" : "CaseList",
"label" : "Cases"
},
"name" : "My Comments",
"id" : "REDCATED",
"currency" : null
},
"factMap" : {
"T!T" : {
"rows" : [ {
"dataCells" : [ {
"value" : "ID",
"label" : "Description"
}, {
"value" : "2014-02-17T22:01:17Z",
"label" : "2/17/2014 4:01 PM"
}, {
"value" : "USER ID",
"label" : "User Name"
} ]
}`
What I need is that label with the timestamp.
And here is my code
#!/usr/bin/perl
use warnings;
use strict;
use WWW::Mechanize;
use WWW::Salesforce;
use Data::Dumper;
use JSON -support_by_pp;
use 5.010;
use Date::Parse;
my $mech = WWW::Mechanize->new();
$mech->agent('Mozilla/5.0');
# Authenticate first via SOAP interface to get a session ID:
my $sforce = eval { WWW::Salesforce->login(
username => 'REDACTED',
password => 'REDACTED' ); };
die "Could not login to SFDC: $#" if $#;
# Get the session ID:
my $hdr = $sforce->get_session_header();
my $sid = ${$hdr->{_value}->[0]}->{_value}->[0];
#Our request
$mech->add_header( "Authorization" => "OAuth $sid" );
$mech->add_header( "X-PrettyPrint" => '1' );
$mech->get("SOME URL THAT RETURNS JSON");
my $content = $mech->content;
my $json = new JSON;
my $json_text = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($content);
Here is what I have currently that grabs the value that I want from $content. All I need is the first result which is why I am killing the loop after the first run. Everytime I have tried this without a loop I get "Not a HASH reference". So all I need to know is the correct syntax for printing out the value of $timestamp.
foreach my $field(#{$json_text->{factMap}->{'T!T'}->{rows}}){
my $now = time();
my $timestamp = str2time($field->{dataCells}[1]->{'label'});
my $diff = int (($now - $timestamp)/60);
my $current = getLoggingTime();
print $current . " \t";
say "Time since last activity: " . $diff . " minutes!" ;
last;
}
sub getLoggingTime {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
my $nice_timestamp = sprintf ( "%04d-%02d-%02d %02d:%02d:%02d",
$year+1900,$mon+1,$mday,$hour,$min,$sec);
return $nice_timestamp;
}
I don't know what your without-a-loop version looks like, but this should work:
my $timestamp = str2time(
$json_text->{factMap}{'T!T'}{rows}[0]{dataCells}[1]{label}
);
Currently, you're looping over the elements of the array referenced by
$json_text->{factMap}{'T!T'}{rows}
...and stopping at the first entry
$json_text->{factMap}{'T!T'}{rows}[0]
...and dereferencing that to get to
$json_text->{factMap}{'T!T'}{rows}[0]{dataCells}[1]{label}

Perl and MongoDB: Inserting Array of Objects into Key-Value Pairs

I'd like to insert into my MongoDB using perl the following BSON structure:
{"name" : "BOB", "stuff" : [{"area1": [1,2,3,4,5]}, {"area2": [5,6,7,8,9]}]}
But have had a hard time finding a good example of this. I tried the following:
#!/usr/bin/perl
use MongoDB;
use MongoDB::Database;
use MongoDB::OID;
my $conn = MongoDB::Connection->new;
my $db = $conn->test;
my $users = $db->real_time10;
$users->insert
({
"name" => "BOB",
"stuff" =>
"area1" => [1,2,3,4,5],
"area2" => [5,6,7,8,9]
});
Which grossly outputs upon query in the mongo shell:
db.real_time10.find()
{ "_id" : ObjectId("4fc912fa000207ec08000000"), "ARRAY(0xa5bdd4)" : "area2", "A
RAY(0x2f2e844)" : null, "name" : "BOB", "stuff" : "area1" }
What is going on? Is there a simple way to do this?
My dream/desired output would be:
> db.real_time10.find()
{ "_id" : ObjectId("4fc912fa000207ec08000000"), "stuff" : {"area1" : [1,2,3,4,5],
"area2": [5,6,7,8,9]}, "name" : "BOB" }
Your missing your anonymous-array-constructor (square-brackets) in your example code - but including them in your BSON example. To get your desired output try:
$users->insert({
"name" => "BOB",
"stuff" => {
"area1" => [1,2,3,4,5],
"area2" => [5,6,7,8,9]
}
});
By excluding the array constructor it builds up a hash with the supplied array key, value pairs so it would be parsed as the following (which matches your data-dump):
{
"name" => "BOB",
"stuff" => "area1",
[1,2,3,4,5] => "area2",
[5,6,7,8,9] => undef
}
Note: an array-ref in scalar context will be seen as a string like "ARRAY(0x6052b8)"
Ah, it's this:
#!/usr/bin/perl
use MongoDB;
use MongoDB::Database;
use MongoDB::OID;
my $conn = MongoDB::Connection->new;
my $db = $conn->test;
my $users = $db->real_time10;
$users->insert({
"name" => "BOB",
"stuff" =>
{"area1" => [1,2,3,4,5],
"area2" => [5,6,7,8,9]}
});
This outputs:
{ "_id" : ObjectId("4fc91f110064e9d40b000000"), "name" : "BOB", "stuff" : { "are
a2" : [ 5, 6, 7, 8, 9 ], "area1" : [ 1, 2, 3, 4, 5 ] } }