why do they want to save a hash in an array? - perl

I saw a very strange piece of code in a perl script used in my project, it's something like:
my $arrayRef = [
A => {AA => 11, AAA => 111},
B => {BB => 11, BBB => 111},
];
IMO, it tries to construct an anonymous array from a hash table. I try to print the array element and here is what I get:
foreach (#$arrayRef )
{
print;
print "\n";
}
A
HASH(0x1e60220)
B
HASH(0x1e71bd0)
which means it treats every element (key&value) in the hash table as a separate element in the anonymous array. However I am really confused about why do they want to save a hash into an array. The ONLY benefit for me is to save some memory if the hash table is really huge. Is this a wedely used perl tricks?
Thanks!

it tries to construct an anonymous array from a hash table.
No, it constructs an anonymous array from a four-element list.
A => {AA => 11, AAA => 111}, B => {BB => 11, BBB => 111}
is exactly the same thing as
'A', {AA => 11, AAA => 111}, 'B', {BB => 11, BBB => 111}
The use of => does imply some sort of relationship, so I suppose they could have used
{ A => {AA => 11, AAA => 111}, B => {BB => 11, BBB => 111} }
or
[ [ A => {AA => 11, AAA => 111} ], [ B => {BB => 11, BBB => 111} ] ]
or any of a million other data structures, but there's way to know why one was chosen over another from what you gave.

It's an anonymous array, in which alternates a string key with an anonymous hash. The answer to your question: it depends on context, a concrete data-structure should help to resolve a concrete problem. So if we have only the data-structure and forget the problem we are trying to resolve, it's harder to imagine why they used this construction.
Perhaps, they needed a "ordered hash of hashes", the array structure makes sure the order, hash not

Related

Why does adding a type before a hash variable that is being built with fat arrow syntax, lead to type check failed error?

Raku is gradual typing language. So the code below:
my %hash = abc => 4.5, abd => 5.5, bcd => 6.4, bce => 3.6;
is the same as:
my Hash %hash = abc => 4.5, abd => 5.5, bcd => 6.4, bce => 3.6;
However, it reports an error:
Type check failed in assignment to %hash; expected Hash but got Rat (4.5)
Why adding a type before a hash variable that build with fat arrow syntax leaded to type check failed error?
When you say my Hash %hash, you're specifying a Hash that will only take Hash as a value. And in your example, you're putting Rats into the hash as values, not Hashes. Which is what the error message is trying to tell you.
Your example would make more sense this way:
my Numeric %hash = abc => 4.5, abd => 5.5, bcd => 6.4, bce => 3.6;
in which you force all values to be Numeric.
Another way of writing that, is:
my %hash is Hash[Numeric] = abc => 4.5, abd => 5.5, bcd => 6.4, bce => 3.6;
The first way is just syntactic sugar for the second.
If you also want to limit the keys, there are also two ways to do that:
my %hash is Hash[Numeric,Str] = abc => 4.5, abd => 5.5, bcd => 6.4, bce => 3.6;
would limit the keys to Str. Note that by default, the type is Str(), aka: coerce anything to Str, which is not the same.
The more syntactic sugary way is:
my Numeric %hash{Str} = abc => 4.5, abd => 5.5, bcd => 6.4, bce => 3.6;
which I think, is more readable as it is clear what the typing of the keys is.

How to create a hash of arrays or hash of hashes

I have a file named Jobs.conf which contains:
JobName: A
JobSize: 100
JobArrival:1
JobExe:100
JobName: B
JobSize: 100
JobArrival:2
JobExe:100
JobName: C
JobSize: 100
JobArrival:3
JobExe:100
JobName: D
JobSize: 100
JobArrival:4
JobExe:100
Is it possible to read this file so each Job is stored in an array and then the 4 arrays are stored in a hash? Would it make more sense to store this as a hash of hashes and is that possible?
The key is to set $/ (the input record separator) properly:
This influences Perl's idea of what a "line" is. Works like awk's RS
variable, including treating empty lines as a terminator if set to the
null string (an empty line cannot contain any spaces or tabs). You may
set it to a multi-character string to match a multi-character
terminator, or to undef to read through the end of file. Setting it
to "\n\n" means something slightly different than setting to "",
if the file contains consecutive empty lines. Setting to "" will
treat two or more consecutive empty lines as a single empty line.
Setting to "\n\n" will blindly assume that the next input character
belongs to the next paragraph, even if it's a newline.
Then we just take advantage of how the records are laid out by split-ing directly into a hash reference:
use strict;
use warnings;
use Data::Dump;
local $/ = "";
my #jobs;
while (<DATA>) {
push(#jobs, {split(/:\s*|\n/)});
}
dd(\#jobs);
__DATA__
JobName: A
JobSize: 100
JobArrival:1
JobExe:100
JobName: B
JobSize: 100
JobArrival:2
JobExe:100
JobName: C
JobSize: 100
JobArrival:3
JobExe:100
JobName: D
JobSize: 100
JobArrival:4
JobExe:100
Or just:
my #jobs = map { {split(/:\s*|\n/)} } <DATA>;
Output:
[
{ JobArrival => 1, JobExe => 100, JobName => "A", JobSize => 100 },
{ JobArrival => 2, JobExe => 100, JobName => "B", JobSize => 100 },
{ JobArrival => 3, JobExe => 100, JobName => "C", JobSize => 100 },
{ JobArrival => 4, JobExe => 100, JobName => "D", JobSize => 100 },
]
An array of hashes (the previous example) would be my preference, but if you wanted a hash of hashes, you'd need to modify the code slightly:
my %jobs;
while (<DATA>) {
my %temp = split(/:\s*|\n/);
$jobs{delete($temp{JobName})} = \%temp;
}
dd(\%jobs);
Output:
{
A => { JobArrival => 1, JobExe => 100, JobSize => 100 },
B => { JobArrival => 2, JobExe => 100, JobSize => 100 },
C => { JobArrival => 3, JobExe => 100, JobSize => 100 },
D => { JobArrival => 4, JobExe => 100, JobSize => 100 },
}

Perl dynamic hash traversal

A hash of (0 or more levels of hash refs of) array refs of hash refs. Note that the level above the leaf nodes will always be array refs, even if they only have one element.
I need to fetch the aggregate sum of VALUE (in an array of array ref) by preserving the order of the hash refs (In the order of insertion).
Examples :
1)
(
A => {
A1 => [
{ VALUE => 10 },
{ VALUE => 20 }
],
B1 => [
{ VALUE => 30 }
],
},
B => {
A1 => [
{ VALUE => 10 }
],
B1 => [
{ VALUE => 5 }
],
},
C => {
A1 => [
{ VALUE => 100 }
],
},
)
The required output of the above structure will be -
(
[A, A1, 30],
[A, B1, 30],
[B, A1, 10],
[B, B1, 5],
.
.
.
.
)
2)
(
A => [
{ VALUE => 10 },
{ VALUE => 20 }
],
B => [
{ VALUE => 30 }
],
)
The required output of the above structure will be -
(
[A, 30],
[B, 30]
)
You need to write a function that will walk your hash structure and compute the necessary sums. For each key in the hash, it needs to make this decision:
If the value of this key is a list ref, then sum up the VALUE elements in the hashes in this list and return [key, sum]
If the value of this hash is a hash ref, then recurse into that hash. If we got a list back from it, append it to our current output and continue.
At the top level (depth 0), print out each list that's returned.
There are a number of details that still need to be resolved, but that ought to get you started on the right track.

what does this ruby code mean?

this code fails:
#user_pages, #users = paginate :users, :per_page => 40, :order => :name
rewriting it like this works:
#users = User.all.paginate(:page => params[:page], :per_page => 40)
but what does #user_pages, #users mean?
I take it that #users is being assigned to #user_pages?
joey
No, #user_pages and #users are two different values returned from an array of values. They are, in effect, value[0] and value[1].
An irb example should help:
MacBook-Pro:~ me$ irb
1.9.3-p429 :001 > a,b = [1,2]
=> [1, 2]
1.9.3-p429 :002 > a
=> 1
1.9.3-p429 :003 > b
=> 2

Assign the values from a list to hash elements

In essence, I want to name the elements of a list.
I can do this:
($hash{'foo'}, $hash{'bar'}, $hash{'baz'}) = listmaker;
but that gets rather lengthy if there are very many elements in a list.
Is there a shorter way to only name the hash once? Perhaps some variation on this:
%hash = ("foo" => "abc", "bar" => "def", "baz" => "ghi");
but with the values coming from the function listmaker? I'm envisioning some sort of map incantation.
Use hash slices:
#hash{'foo', 'bar', 'baz'} = listmaker
or
#hash{qw( foo bar baz )} = listmaker