This question already has answers here:
Get the length of an array within a Perl hash
(3 answers)
Closed 7 years ago.
Here is my code:
#!/usr/bin/perl
use Net::Twitter;
use JSON;
use LWP::Simple;
use XML::Bare;
use Data::Dumper;
# keys for twitter
$consumer_key = "key";
$consumer_secret = "key";
$token = "key-key";
$token_secret = "key";
# As of 13-Aug-2010, Twitter requires OAuth for authenticated requests
my $nt = Net::Twitter->new(
traits => [qw/API::RESTv1_1/],
# traits => [qw/API::Search/],
consumer_key => $consumer_key,
consumer_secret => $consumer_secret,
access_token => $token,
access_token_secret => $token_secret,
);
$UserID = 46562311;
my $IDs = $nt->friends_ids({user_id => $UserID});
print Dumper $IDs->{ids};
The output is:
$VAR1 = [
1243478918,
472407213,
1152523333,
18080969,
36843988,
24467012,
322990625,
15492359,
2244340904,
22938914,
151180133,
58545637,
62513246,
28412286,
5746452,
17104751,
1636590253,
25073877,
8161232,
2384071,
13,
93957809,
22330739,
44196397,
132961448,
754500,
94384796,
59604041,
386854967,
15485441,
190617492,
226237599,
114485232,
190486752,
18645153,
326350862,
546915948,
1927794380,
244360712,
254674228,
43593,
17242168,
17268874,
117539435,
116737145,
326642243,
1010165784,
19583340,
7936522,
166739404,
50374439,
593893034,
1244526223,
783214,
382267114,
299743215,
16129880,
20536157,
17006157,
2249234689,
26761757,
17919972,
2244994945,
1526228120,
11348282,
14159148,
50393960,
1339835893,
409685881,
2469260288,
1012494116,
270816968,
813286,
2546660556,
518542127,
794611698,
108962082,
1626691956,
734314441,
20351217,
1692371666,
774980724,
865699670,
1958038938,
826539409,
805891104,
14749606,
391858548,
26693596
];
How do I count the length of this array? I used "length $IDs->{ids}" but it only gave me 21 which is obviously wrong.
You can use scalar builtin function:
print scalar #{ $IDs->{ids} };
It forces it's argument to be interpreted in scalar context. And as you know array in scalar context is evaluated to it's length.
Related
What I want here is for #{$allHash{$key1}} to be ["item1", "item2"].
Pushing doesn't work, and all the print statements are to try and find where the pushed items went.
Using -> notation in the push is even worse, it makes $temp[0][0] and line 24 show an array instead of the item.
#use strict; # I've turned these off here to make the code easier to read
#use warnings;
my %allHash = ();
my $key1 = "key1";
my $item1 = "item1";
my $item2 = "item2";
#if (!exists($allHash{key1})) {$allHash{key1}=();}; # makes no difference, the array autovivefies anyway
push (#{$allHash{$key1}}, $item1); # push 1st item
print"\n\nat11: pushed $key1, $item1";
my #temp = $allHash{$key1};
print"\nat13:temp=#temp, length=",0+#temp, ", temp[0]=$temp[0], temp[0][0]=$temp[0][0]";
print"\nat14: allHash{$key1}[0]= $allHash{$key1}[0]";
print"\nat15: allHash{$key1}[1]= $allHash{$key1}[1]";
print"\nat16: allHash{$key1}[0][0]= $allHash{$key1}[0][0]";
print"\nat17: allHash{$key1}[1][0]= $allHash{$key1}[1][0]";
print"\nat18: allHash{$key1}[0][1]= $allHash{$key1}[0][1]\n";
print"\n----------------";
push (#{$allHash{$key1}}, $item2); # push 2d item
print"\n\nat21: pushed $key1, $item2";
#temp = #{allHash{$key1}};
print"\nat23:temp=#temp, length=",0+#temp, ", temp[0]=$temp[0], temp[0][0] =$temp[0][0]";
print"\nat24: allHash{$key1}[0]= $allHash{$key1}[0]";
print"\nat25: allHash{$key1}[1]= $allHash{$key1}[1], allHash{$key1}[1][0] =$allHash{$key1}[1][0]";
print"\nat26: allHash{$key1}[0][0]= $allHash{$key1}[0][0]";
print"\nat27: allHash{$key1}[1][0]= $allHash{$key1}[1][0]";
print"\nat28: allHash{$key1}[0][1]= $allHash{$key1}[0][1]\n";
The output from the above program is:
at11: pushed key1, item1
at13:temp=, length=1, temp[0]=ARRAY(0x331eb8), temp[0][0]=item1
at14: allHash{key1}[0]=item1
at15: allHash{key1}[1]=
at16: allHash{key1}[0][0]=
at17: allHash{key1}[1][0]=
at18: allHash{key1}[0][1]=
----------------
at21: pushed key1, item2
at23:temp=ARRAY(0x331ee8), length=1, temp[0]=ARRAY(0x331ee8), temp[0][0]=item1
at24: allHash{key1}[0]=item1
at25: allHash{key1}[1]= ARRAY(0x332020), allHash{key1}[1][0]=
at26: allHash{key1}[0][0]=
at27: allHash{key1}[1][0]=
at28: allHash{key1}[0][1]=
What's bizarre is that this almost identical code from another of my programs works perfectly.
%hedgeHash = (); # collect the members of each hedge as an array, using stub as key
for (my $i=0; $i<#options; $i++)
{ $Hstub = $options[$i][$iStub];
push #{$hedgeHash{$Hstub}}, $i; # hedgehash should contain array of members of the hedge.
}
What's even more bizarre is that if I remove the parentheses from the push statement, I no longer get 'item1' as the output of #temp and on lines 14 and 24, but get another array! WTF??
Please see a sample code bellow demonstrating a use of hash of arrays.
Indeed OP's coding style makes code reading somewhat difficult.
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my %allHash;
my $key1 = 'key1';
my $item1 = 'item1';
my $item2 = 'item2';
my $item3 = 'item3';
my $item4 = 'item4';
my $item5 = 'item5';
push #{$allHash{$key1}}, $item1;
push #{$allHash{$key1}}, $item2;
$allHash{$key1}[2] = $item3;
$allHash{$key1}[3] = [$item4,$item5];
say Dumper(\%allHash);
Output
$VAR1 = {
'key1' => [
'item1',
'item2',
'item3',
[
'item4',
'item5'
]
]
};
I need to evaluate a series of strings that I want to convert into a hash of arrays. Take into account that, in this case, I want to add an array to an entry in a hash that it is already storing an array. I need to get the following hash:
ConfigurationHash{'Editor'} = (John, Mary, Jane, Peter)
I have stripped down my code to this example:
use strict;
use warnings;
my %ConfigurationHash;
my $String1 = "Editor=John,Mary";
my $String2 = "Editor=Jane,Peter";
my #Line1 = split ("=", $String1);
my #Line2 = split ("=", $String2);
my $Variable1 = #Line1[0];
my $Value1 = #Line1[1];
my $Variable2 = #Line2[0];
my $Value2 = #Line2[1];
my #Values1Array = split(",", $Value1);
my #Values2Array = split(",", $Value2);
if ( ! exists $ConfigurationHash{$Variable1} ) {
$ConfigurationHash{$Variable1} = #Values1Array;
}
else {
push (#ConfigurationHash{$Variable1}, #Values1Array);
}
which produces the following error:
Experimental push on scalar is now forbidden at ./test.pl line 25, near "#Values1Array)"
Execution of ./test.pl aborted due to compilation errors.
I know that the problem lies in references/dereferences, but my knowledge of perl is so basic that I'm not able to figure how to get there by myself.
Could anybody show me how to do it? I would also appreciate if you could show me how to iterate the values of the array in the hash once it is created.
It's unclear why you have $String2 and its derivatives in your code as they are never used. This code processes both strings
You simply need to push the list of values to the array corresponding to $Variable1 (dreadful choice of identifier) in the hash. Accomplish this by dereferencing the array element
use strict;
use warnings;
my %config;
my $s1 = 'Editor=John,Mary';
my $s2 = 'Editor=Jane,Peter';
for ( $s1, $s2 ) {
my ($key, #values) = split /[=,]/;
push #{ $config{$key} }, #values;
}
use Data::Dumper;
print Dumper \%config;
output
$VAR1 = {
'Editor' => [
'John',
'Mary',
'Jane',
'Peter'
]
};
This line isn't doing what you think it does.
$ConfigurationHash{$Variable1} = #Values1Array;
If you printed out what $ConfigurationHash{$Variable1} contains you'll find it only contains the size of #Values1Array.
You should be fine to use push but with a slight modification to what you've written.
push #{$ConfigurationHash{$Variable1}}, #Values1Array;
I've also removed the brackets as you don't need them.
As for iterating over the array, it is no different to iterating over a regular array. You were likely having problems iterating over it before as you didn't have an array
foreach my $whatever (#{$ConfigurationHash{$Variable1}})
{
# Code
}
Thank you to all who posted answers. #Borodin, you're right, I missed a second block that used $String2 and its derivatives, but I think it was obvious it was at the end and was similar to the if-else block in my original code.
Thank you, #chris-turner, for giving me the hint on how to use push the right way and pointing out the error in the $ConfigurationHash{$Variable1} = #Values1Array;
With all these contributions I figured out that the right code I was expecting is:
use strict;
use warnings;
my %ConfigurationHash;
my $String1 = "Editor=John,Mary";
my $String2 = "Editor=Jane,Peter";
my #Line1 = split ("=", $String1);
my #Line2 = split ("=", $String2);
my $Variable1 = $Line1[0];
my $Value1 = $Line1[1];
my $Variable2 = $Line2[0];
my $Value2 = $Line2[1];
my #Values1Array = split(",", $Value1);
my #Values2Array = split(",", $Value2);
if ( ! exists $ConfigurationHash{$Variable1} ) {
$ConfigurationHash{$Variable1} = \#Values1Array;
}
else {
#push (#ConfigurationHash{$Variable1}, #Values1Array);
push #{$ConfigurationHash{$Variable1}}, #Values1Array;
}
if ( ! exists $ConfigurationHash{$Variable2} ) {
$ConfigurationHash{$Variable2} = \#Values2Array;
}
else {
#push (#ConfigurationHash{$Variable2}, #Values2Array);
push #{$ConfigurationHash{$Variable2}}, #Values2Array;
}
use Data::Dumper;
print Dumper \%ConfigurationHash;
Which outputs the following:
$VAR1 = {
'Editor' => [
'John',
'Mary',
'Jane',
'Peter'
]
};
I load some variables from the URL and want to check in my CGI script whether are they initialized. I quickly found out that I can not put uninitialized values into an list in Perl.
My approach was simply to iterate through the list and use a switch variable $sucessDOM (1 if all data had been initialized and 0 elsewhere).
I came up with this:
### Read data from HTML
my $mailinglist = param( 'mailinglist' );
my $firstname = param( 'firstname' );
my $lastname = param( 'lastname' );
my $mail = param( 'mail' );
my $sucessDOM = 0;
my #DOM = { $mailinglist, $firstname, $lastname, $mail };
### Data validation
for my $data ( #DOM ) {
if ( $data eq undef ) {
$sucessDOM = $sucessDOM + 1;
}
if ( $sucessDOM = #DOM ) {
print "#DOM\n";
$sucessDOM = 1;
}
else {
$sucessDOM = 0;
}
}
The output is as follows
[Fri Dec 22 20:30:40 2017] read_form.cgi: Use of uninitialized value $mailinglist in anonymous hash ({}) at ./read_form.cgi line 20.
[Fri Dec 22 20:30:40 2017] read_form.cgi: Use of uninitialized value $lastname in anonymous hash ({}) at ./read_form.cgi line 20.
[Fri Dec 22 20:30:40 2017] read_form.cgi: Use of uninitialized value in string eq at ./read_form.cgi line 24.
HASH(0x55c8a73eeea8)
I also cannot understand why are there errors for only two values in the array if they are all uninitialized, as I run the script directly without passing any values.
You have at least four problems with your code:
First, {} makes an anonymous hash and returns a reference to it; this is a single value that ends up in #DOM. The warnings are because hash keys have to be strings, and warn if they are undef. You should be assigning like
my #DOM = ( $mailinglist, $firstname, $lastname, $mail );
Second, eq compares strings, so it would convert undef to ''. To test if $data is undef, do
if (! defined $data) {
Third, you are checking if all the array elements were successful inside the for loop (where that will not be true on any but the last iteration of the loop). Move the if ($successDOM... block to after the for loop.
Fourth, = is just an assignment operator; use == for numeric comparison:
if ($successDOM == #DOM) {
Further to finding an answer to my earlier question Perl: slicing an array of hashes, I am stuck again and unable to see what I have done wrong.
What I have is
Array( Array0(Hash0,Hash1),Array1(Hash0,Hash1),Array2(Hash0,Hash1)...)
use strict;
use warnings;
my #DDs = ();
my #Ds = ();
my %hsh = ();
my %dot1 = ( 'x' => 1, 'y' => 2, 'r' => 3 );
my %dot2 = ( 'x' => 4, 'y' => 5, 'r' => 6 );
my %dot3 = ( 'x' => 7, 'y' => 8, 'r' => 9 );
my %dot4 = ( 'x' => 1.1, 'y' => 1.2, 'r' => 1.3 );
my %dot5 = ( 'x' => 2.1, 'y' => 2.2, 'r' => 2.3 );
my %dot6 = ( 'x' => 3.1, 'y' => 3.2, 'r' => 3.3 );
my %dot7 = ( 'x' => 4.1, 'y' => 4.2, 'r' => 4.3 );
my %dot8 = ( 'x' => 5.1, 'y' => 5.2, 'r' => 5.3 );
my #dotsA = ( \%dot1, \%dot2 );
my #dotsB = ( \%dot3, \%dot4 );
my #dotsC = ( \%dot5, \%dot6 );
my #dotsD = ( \%dot7, \%dot8 );
my %Ds = ( \#dotsA, \#dotsB, \#dotsC, \#dotsD );
#DDs = $Ds[1]; #expect #dotsB with scalar of 2
###"Can't use an undefined value as HASH reference" error here
%hsh = %{ $DDs[0] }; #expect %dot3
print scalar #DDs, "\n"; #expect 2 but has value of 1
print $hsh{'x'}, "\n";
Reference found where even-sized list expected at /Users/schwern/tmp/test.plx line 10.
Line 10 is this:
my %dot1 = {'x'=>1,'y'=>2,'r'=>3};
This is Perl's cryptic way of saying you fed a hash reference to a hash. Perl, unfortunately, distinguishes very strongly between things and references to that thing.
%dot1 is a hash. It takes a list and turns it into a hash. A list like ( x => 1, y => 2, r => 3). { x => 1, y => 2, r => 3 } creates a hash reference. That's a single thing, a scalar. It's like saying my %dot1 = (42). It doesn't make any sense.
%dot1 is a hash, it wants a list like (x => 1, y => 2)
$dot1 is a scalar, it can store a hash reference like { x => 1, y => 2 }.
my %Ds = (\#dotsA,\#dotsB,\#dotsC,\#dotsD);
A hash requires a key and a value, pairs. last_name => "Schwern". When you give it a bunch of array references like that, it will read them as key1, value1, key2, value2... but what is it using as the key? It's using the stringification of that reference, something like ARRAY(0x7fb721800468).
If you asked for $D{\#dotsA} you'll get back a reference to #dotsB. You will not be able to get #dotsA back, a Perl hash key is just a string, not a reference.
This isn't a very good way to store an array in a hash. I'm not sure what you're trying to accomplish, but you probably want to reference them by name.
# A hash of lists.
my %Ds = ( A => \#dotsA, B => \#dotsB, C => \#dotsC, D => \#dotsD );
# Get back a reference to #dotsA.
my $dotsA = $Ds{A};
But looking at the following code, #DDs = $Ds[1];, I think you meant to initialize #Ds instead of %Ds.
#Ds = (\#dotsA,\#dotsB,\#dotsC,\#dotsD);
And now the following works... sort of. More later.
#DDs = $Ds[1]; #expect #dotsB with scalar of 2
Unlike in PHP, hashes and arrays are totally different things. my #Ds and my %Ds declare totally different variables. It doesn't help that you access them both with $Ds. In Perl5, the sigil indicates what's going to get returned. $Ds[1] and $Ds{foo} both use $Ds because they're returning a scalar. #Ds[1,2] and #Ds{(foo, bar)} use #Ds because they're returning a list (known as a slice). Confusing, but that's how it works.
#DDs = $Ds[1]; #expect #dotsB with scalar of 2
You're not getting #dotsB, you're getting a reference to #dotsB. All complex data structures in Perl store references, not the actual value. This is like $DDs[0] = \#dotsB. If you want to get the actual value you have to dereference it.
#DDs = #{$Ds[1]}; # Now #DDs has a copy of #dotsB
And finally it works.
#!/usr/bin/perl
use strict;
use warnings;
use v5.10; # for say()
my %dot1 = ('x'=>1,'y'=>2,'r'=>3);
my %dot2 = ('x'=>4,'y'=>5,'r'=>6);
my %dot3 = ('x'=>7,'y'=>8,'r'=>9);
my %dot4 = ('x'=>1.1,'y'=>1.2,'r'=>1.3);
my %dot5 = ('x'=>2.1,'y'=>2.2,'r'=>2.3);
my %dot6 = ('x'=>3.1,'y'=>3.2,'r'=>3.3);
my %dot7 = ('x'=>4.1,'y'=>4.2,'r'=>4.3);
my %dot8 = ('x'=>5.1,'y'=>5.2,'r'=>5.3);
my #dotsA = (\%dot1,\%dot2);
my #dotsB = (\%dot3,\%dot4);
my #dotsC = (\%dot5,\%dot6);
my #dotsD = (\%dot7,\%dot8);
my #Ds = (\#dotsA,\#dotsB,\#dotsC,\#dotsD);
my #DDs = #{$Ds[1]}; #expect #dotsB
my %hsh = %{$DDs[0]}; #expect %dot3
say scalar #DDs; #expect 2
say $hsh{'x'};
I would also advise that you get comfortable working directly with references since that's what complex data structures are: references. Converting back and forth from references to values is confusing. Working with references is one less thing to convert in your code, in your head, and less copying done in your program.
#!/usr/bin/perl
use strict;
use warnings;
use v5.10; # for say()
my $dot1 = {'x'=>1,'y'=>2,'r'=>3};
my $dot2 = {'x'=>4,'y'=>5,'r'=>6};
my $dot3 = {'x'=>7,'y'=>8,'r'=>9};
my $dot4 = {'x'=>1.1,'y'=>1.2,'r'=>1.3};
my $dot5 = {'x'=>2.1,'y'=>2.2,'r'=>2.3};
my $dot6 = {'x'=>3.1,'y'=>3.2,'r'=>3.3};
my $dot7 = {'x'=>4.1,'y'=>4.2,'r'=>4.3};
my $dot8 = {'x'=>5.1,'y'=>5.2,'r'=>5.3};
my $dotsA = [$dot1,$dot2];
my $dotsB = [$dot3,$dot4];
my $dotsC = [$dot5,$dot6];
my $dotsD = [$dot7,$dot8];
my $Ds = [$dotsA,$dotsB,$dotsC,$dotsD];
my $DDs = $Ds->[1]; #expect $dotsB
my $hsh = $DDs->[0]; #expect $dot3
say scalar #$DDs; #expect 2
say $hsh->{'x'};
You should review perlreftut and the Nested Data Structures chapter of Modern Perl.
In my Yii2 Project I have an array for example
$array = [];
$array [] = 8 , 3, 6
So when I print out the array is
[8,3,6]
So when I use the same in a where statement it jumbles up.
$class = ModelClass::find()->where(['array_no' => $array])->all
So when I print out class I get the output in asc order sorted..
I get the information of
3 in the first
6 in the second place
8 in the third place.
How can i stop this from happening. I want them to return my output in the same order as array
You should use ORDER BY FIELD(), e.g. :
$models = ModelClass::find()
->where(['array_no' => $array])
->orderBy(new \yii\db\Expression('FIELD (array_no, '.implode(',', $array).')'))
->all();