Perl Concatenating 2 hashes based on a certain key - perl

Hi I have two hashes %Asset & %Activity
%Asset
Name,Computer Name
David,X
Clark,Y
Sam,Z
%Activity
Name,Activity
David,A
Clark,B
Sam,C
David,D
Clark,E
Sam,F
The second hash has the name repeated multiple times (can be more than 2) .. I want to get a hash with the concise infromation.. something like
Name,Computer Name,Activity
David,X,A&D
Clark,Y,B&E
Sam,Z,C&F
my idea in a pseudo code kind of way is;
foreach (#Activity{qw[Name]}) {
push #Asset{qw[Name Activity]}, $Activity['Activity']
}

What you want is a hash of hashes. Conceptually, you'd combine all information about an asset into a single hash.
my %dave = (
name => "Dave",
computer_name => "X",
activity => "A"
);
Then this goes into a larger hash of all assets keyed by their name.
$Assets{$dave{name}} = \%dave;
If you want to find Dave's activity...
print $Assets{Dave}{activity};
You can pull out all information about Dave and pass it around as a hash reference.
my $dave = $Assets{Dave};
print $dave->{activity};
This sort of structure inevitably leads to modelling your assets as objects.
You can learn more about hashes of hashes in the Perl Data Structures Cookbook.

Related

Removing a key from a Perl hash

I have a hash in which its keys are hashes. I want to rename some of the keys inside the primary hash by adding a key with the desired name and deleting the unwanted key. I succeeded in adding a key, but I'm unable to delete the original key.
This statement isn't working
delete $primary_hash{$sec_hash_key};
If I print the value of $primary_hash{$sec_hash_key} it's returning $HASH(0X*). I don't know what is missing in syntax?
In Perl, hash keys are always strings. If you specify a non-string object as a hash key, perl will stringify it to be able to use it as a key. Therefore, when you say:
I have hash in which it's [sic] keys are hashes
you are wrong. They are not hashes, they are strings.
Now, if you did something like:
my %h = (a => 1);
my %g = (%h => 2);
That would have created %g as:
(a => 1, 2 => undef);
If, instead, you did %g = (\%h => 2), that would have created something along the lines of:
%g = (
'HASH(0x7ff92882cbd8)' => 2
);
Note that the key is a string. You cannot go back to the data structure from that string.
What do you mean by 'delete'? Free the memory, or just want the
key to be undefined, when checking for it in an if statement?
The latter you can achieve my setting the key undef.
$primary_hash{$sec_hash_key} = undef;.
But please provide a full working example of your problem, so
it can be reproduced.

What does this mean in Perl 1..$#something?

I have a loop for example :
for my $something ( #place[1..$#thing] ) {
}
I don't get this statement 1..$#thing
I know that # is for comments but my IDE doesn't color #thing as comment. Or is it really just a comment for someone to know that what is in "$" is "thing" ? And if it's a comment why was the rest of the line not commented out like ] ) { ?
If it has other meanings, i will like to know. Sorry if my question sounds odd, i am just new to perl and perplexed by such an expression.
The $# is the syntax for getting the highest index of the array in question, so $#thing is the highest index of the array #thing. This is documented in perldoc perldata
.. is the range operator, and 1 .. $#thing means a list of numbers, from 1 to whatever the highest index of #thing is.
Using this list inside array brackets with the # sigill denotes that this is an array slice, which is to say, a selected number of elements in the #place array.
So assuming the following:
my #thing = qw(foo bar baz);
my #place = qw(home work restaurant gym);
then #place[1 .. $#thing] (or 1 .. 2) would expand into the list work, restaurant.
It is correct that # is used for comments, but not in this case.
it's how you define a range. From starting value to some other value.
for my $something ( #place[1..3] ) {
# Takes the first three elements
}
Binary ".." is the range operator, which is really two different
operators depending on the context. In list context, it returns a list
of values counting (up by ones) from the left value to the right
value. If the left value is greater than the right value then it
returns the empty list. The range operator is useful for writing
foreach (1..10) loops and for doing slice operations on arrays. In the
current implementation, no temporary array is created when the range
operator is used as the expression in foreach loops, but older
versions of Perl might burn a lot of memory when you write something
like this:
http://perldoc.perl.org/perlop.html#Range-Operators

What does #data actually contain in PDF::Report::Table $table_write->addTable(#data);?

I think I've got the gist of creating a table using Perl's PDF::Report and PDF::Report::Table, but am having difficulty seeing what the 2-dimensional array #data would look like.
The documentation says it's a 2-dimensional array, but the example on CPAN just shows an array of arrays test1, test2, and so on, rather than the example showing data and formatting like $padding $bgcolor_odd, and so on.
Here's what I've done so far:
$main_rpt_path = "/home/ics/work/rpts/interim/mtr_prebill.rpt";
$main_rpt_pdf =
new PDF::Report('PageSize' => 'letter', 'PageOrientation' => 'Landscape',);
$main_rpt_tbl_wrt =
PDF::Report::Table->new($main_rpt_pdf);
Obviously, I can't pass a one dimensional array, but I have searched for examples and can only find the one in CPAN search.
Edit:
Here is how I am trying to call addTable:
$main_rpt_tbl_wrt->addTable(build_table_writer_array($pt_column_headers_ref, undef));
.
.
.
sub build_table_writer_array
# $data -- an array ref of data
# $format -- an array ref of formatting
#
# returns an array ref of a 2d array.
#
{
my ($data, $format) = #_;
my $out_data_table = undef;
my #format_array = (10, 10, 0xFFFFFF, 0xFFFFCC);
$out_data_table = [[#$data],];
return $out_data_table;
}
and here is the error I'm getting.
Use of uninitialized value in subtraction (-) at /usr/local/share/perl5/PDF/Report/Table.pm line 88.
at /usr/local/share/perl5/PDF/Report/Table.pm line 88
I cannot figure out what addTable wants for data. That is I am wondering where the formatting is supposed to go.
Edit:
It appears the addData call should look like
$main_rpt_tbl_wrt->addTable(build_table_writer_array($pt_column_headers_ref), 10,10,xFFFFFF, 0xFFFFCC);
not the way I've indicated.
This looks like a bug in the module. I tried running the example code in the SYNOPSIS, and I got the same error you get. The module has no real tests, so it is no surprise that there would be bugs. You can report it on CPAN.
The POD has bugs, too.
You increase your chances of getting it fixed if you look at the source code and fix it yourself with a patch.

join() function is returning the type followed by a hex number instead of a concatenated string

In essence, I want to take an array and create a single string with the elements of said array separated by a newline.
I have an array named $zones. Outputting the reference to $zones confirms it's an array.
The following code:
print_log(Dumper($zones));
print_log('-------');
print_log(Dumper(join("\n",$zones)));
results in the following output
[2013-06-15 16:23:29 -0500] info [dnsadmin] $VAR1 = [
'fake.com25',
'fake.com2',
'fake.com27',
'fake.com43',
'fake.com41',
'fake.com40',
'fake.com39',
'fake.com37',
'fake.com36',
'fake.com35',
'fake.com31',
'fake.com56',
'fake.com55',
'fake.com54',
'fake.com53',
'fake.com52',
'fake.com51',
'fake.com50',
'fake.com49',
'fake.com48',
'fake.com42',
'fake.com38',
'fake.com34',
'fake.com33',
'fake.com32',
'fake.com30',
'fake.com29',
'fake.com28',
'fake.com26',
'fake.com24',
'fake.com23',
'fake.com69',
'fake.com68',
'fake.com67',
'fake.com66',
'0',
'fake.com44',
'fake.com45',
'fake.com46',
'fake.com278'
];
[2013-06-15 16:23:29 -0500] info [dnsadmin] -------
[2013-06-15 16:23:29 -0500] info [dnsadmin] $VAR1 = 'ARRAY(0x170cf0d8)';
I really don't want to loop over this array manually. Can someone explain why the join() function is returning the name of the type along with a hex number?
How to do is explained well by user1937198, but why it works this way?
It's simple:
$zones is not an array. It's an array reference.
join works on lists. So if you do:
join("\n",$zones)
You essentially are calling join on a single-element list. And the element is a reference, which happens to stringify to ARRAY(0x170cf0d8).
To make it work correctly you have to dereference it, and it is done by prefixing with real datatype (# or %, or in some cases $).
This can be written like this: #$zones, or (some, including me, say that it's more readable) as: #{ $zones }.
This is important when you're having nested structures, because while you can have plain array as a variable, when you're dealing with nested data structures, it's always references.
what you want is join("\n",#{$zones}))
$zones is array reference and to join array values you have to dereference it first by prefixing scalar $zones with #
print_log(Dumper(join("\n",#$zones)));
For more info there is short tutorial on references:
http://perldoc.perl.org/perlreftut.html#NAME

Perl hash of hash of lists from Net::LDAP to a 'filtered' list

The Net::LDAP module for Perl provides an Net::LDAP::Search object. Its as_struct method returns the structure below.
Multiple entries as
$entry{dn=...} =
ref {cn} = ref {name}
ref {l} = ref {city}
ref{mail} = ref {xxxxxx}
An example:
uid=pieterb,ou=People,dc=example,dc=org {key of first hash = dn in ldap}
uid=pieterb {key=uid}
cn=Pieter B. {key=cn}
uidNumber=1000 {key=uidNumber}
gidNumber=4000 {key=gidNumber}
uid=markc,ou=People,dc=example,dc=org {key of first hash = dn in ldap }
uid=markc {key=uid}
cn=Mark Cole {key=cn}
uidNumber=1001 {key=uidNumber}
gidNumber=4000 {key=gidNumber}
However, the interface uses UI::Dialog which expects a list in the format below (radiolist/checklist), with data coming from the attribute values in the LDAP server
list => [
'Pieter B.', ['uid=pieterb,ou=People,dc=example,dc=org',0],
'Mark Cole', ['uid=markc,ou=People,dc=example,dc=org',0],
'cn_value(openldap)',['dn_value',0],
'givenname_value(activedirectory)',['dn_value',0]
]
It is very hard to guess what you want, but I think it is a list of the LDAP attribute names versus their values.
You should look at Data::Dumper to examine and present the data structures you are dealing with.
You don't mention what to do if the data you get from the search contains multiple Distinguished Names, or multiple values for an attribute, but this code simply takes the first DN and the first value in lists of attribute values to generate a list of lists.
I have little doubt that this isn't exactly what you need, and if you specify your requirement better we will be able to help further.
my $data = $msg->as_struct;
my $entry = (values %$data)[0];
my #attributes = map {
$_, [$entry->{$_}[0], 0]
} keys %$entry;
$dialog->checklist(list => \#attributes);