looping through an array of hashes in a hash - arrays

I have the following code that uses references to hashes:
sub readAll {
my ( $main, $dbh ) = #_;
my #SessSeq = ();
my $sql;
my $rec = 0;
$sql = "SELECT * FROM sys_table ";
my $sth = PrepAndExecuteQuery( $dbh, $sql );
while ( my $result = $sth->fetchrow_hashref() ){
push #SessSeq, $result;
$rec++;
}
$$main{_SessSeq} = \#SessSeq;
}
Above code works. i get an array of hashes in the main hash
I'm struggling to retrieve the data due to my lack of knowledge.
this doesnt seem to work:
foreach my $ses ( #($$main{_SessSeq}) ){
print STDERR Dumper $ses;
}
what am i doing wrong?

Assuming that your foreach my $ses loop is inside the readAll subroutine, the only thing you are doing wring is to use use parentheses ( ... ) instead of braces { ... }in your dereferencing
$$main{_SessSeq} would be very much better written in modern terms as $main->{_SessSeq}, but both evaluate to the same thing: a reference to an array of hashes with the data from a database table row in each hash
The correct loop will look like this
for my $ses ( #{ $main->{_SessSeq} } ) {
print STDERR Dumper $ses;
}
but there is no real advantage over writing just
print STDERR Dumper $main->{_SessSeq}
You say nothing about what this doesn't seem to work might mean, but print Dumper $ses will output the contents of a table row each time around the loop
If you need any further help then you must describe the problem properly, showing the output that you're getting and describing carefully what you expect

Related

Perl array - trying to parse quotes in proper array elements

I have been struggling with this for a while in a Perl script I have. Probably a slam dunk for you Perl experts, and probably should be easier, but I can't quite crack the nut on this. I might be needing to split this, not sure.
My array code as is follows.
while ( my $row = $query_handle->fetchrow_hashref('NAME_lc') ){
push #query_output, $row;
push (#{portfo->{label}},$row->{data},$row->{label});
}
And then my print of the array is as follows:
print "array here--";
print "[";
foreach (#{portfo->{label}}) {
#(#{portfo->{label}},$row->{data});
print "\{\"data\":";
print "".$_.",";
print "\"label\":";
print "\"".$row[1]."\"\},";
}
print "]";
print "\n";
And then my output looks like this:
[{"data":2943,"label":""},{"data":CDI3,"label":""},
{"data":1,"label":""},{"data":COS-COS2,"label":""},
{"data":1087,"label":""},{"data":COS1,"label":""},
{"data":5183,"label":""},{"data":COS2,"label":""},
{"data":2731,"label":""},{"data":CULB,"label":""},{"data":1,"label":""},
{"data":EQUIT,"label":""},{"data":4474,"label":""},
{"data":Network,"label":""},]
I am trying to make the apha-num string array items like CDI3, COS1, COS2, etc in quotes, in the label part. Somehow I'm getting it separated. Meanwhile, I do want the numeric values left with the "data" name pair.
[{"data":2943,"label":""},{"data":"CDI3","label":""},
{"data":1,"label":""},{"data":"COS-COS2","label":""},
{"data":1087,"label":""},{"data":"COS1","label":""},
{"data":5183,"label":""},{"data":"COS2","label":""},
{"data":2731,"label":""},{"data":"CULB","label":""},{"data":1,"label":""},
{"data":"EQUIT","label":""},{"data":4474,"label":""},
{"data":"Network","label":""}]
I'm sure it's a simpler fix that I'm making it but so far no luck. Any tips would be greatly appreciated!
Thanks!
use JSON::XS qw( encode_json );
my #data;
while ( my $row = $query_handle->fetchrow_hashref('NAME_lc') ) {
# If $row->{data} is a number,
# make sure it's stored as a number
# so that it gets serialized as a number.
$row->{data} += 0 if $row->{data} =~ /^\d+\z/;
push #data, $row;
}
print(encode_json(\#data));
Or
my $data = $query_handle->fetchall_arrayref({ data => 1, label => 1 });
for my $row (#$data) {
$row->{data} += 0 if $row->{data} =~ /^\d+\z/;
}
print(encode_json($data));
Or if you ensure the fields names are returned as lowercase[1],
my $data = $query_handle->fetchall_arrayref({});
for my $row (#$data) {
$row->{data} += 0 if $row->{data} =~ /^\d+\z/;
}
print(encode_json($data));
This can be done using $dbh->{FetchHashKeyName} = 'NAME_lc'; or AS `label`.

Match array based on existing array

I have two arrays,
my #test = ('a','b','c','d','e',f,'g','h');
my #test2 = ('h','b','d');
I'm attempting to loop through the array #test, and match elements against those in #test2, deleting those elements that do not exist.
I have the following code:
foreach my $header (#test) {
if( exists $test2[$header]){
# do nothing
}
else {
delete $test[$header];
}
}
So, I want array #test to look like this (ignore the fact this could be sorted alphabetically):
my #test = ('b','d','h');
However currently my array remains the same after the foreach loop, can anyone suggest why?
You're misunderstanding what 'header' is set to. It's set to (an alias of) the value in the array.
So
foreach my $header (#test) {
print $header,"\n";
}
Will give you a, b, c etc.
However, then you're trying to access $test2['a'] which isn't valid, because it should be numeric.
So actually, a good case study in why you should use strict and warnings because this would have told you the problem:
Argument "a" isn't numeric in array or hash lookup at
Argument "b" isn't numeric in array or hash lookup at
etc.
So it's not actually doing anything.
You shouldn't use delete in this way either though, because you're deleting from a list whilst iterating it. That's not good, even without the fact that it's nonsense to use a letter as an array index.
You could do it like this instead though:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my #test = ('a','b','c','d','e','f','g','h');
my #test2 = ('h','b','d');
my %is_in_test2 = map { $_ => 1 } #test2;
#test = grep { $is_in_test2{$_} } #test;
print Dumper \#test;
If you do want to iterate by index, you can do it like this:
for my $index ( 0..$#test ) {
print "$index => $test[$index]\n";
}
But I would still suggest that deleting whilst iterating isn't a great plan, because modifying a thing you're iterating it ( and aiming to resize the array) is a good way to end up with strange bugs.
So whilst you could:
for my $index ( 0..$#test ) {
print "$index => $test[$index]\n";
delete $test[$index] if not $is_in_test2{$test[$index]};
}
print Dumper \#test;
What you'll end up with is:
$VAR1 = [
undef,
'b',
undef,
'd',
undef,
undef,
undef,
'h'
];
For the more general case there is a a FAQ: How do I computer the difference/intersection of two arrays
use strict;
use warnings;
my #test = ('a','b','c','d','e','f','g','h');
my #test2 = ('h','b','d');
foreach my $header (#test) {
foreach my $header2 (#test2) {
if( $header eq $header2) {
print "$header,"; #prints only existing values
}
else {
#doNothing
}
}
}
Note: This method is not feasible when you are dealing an array with huge elements.

More clarification about the usage of split in Perl

I have this following input file:
test.csv
done_cfg,,,,
port<0>,clk_in,subcktA,instA,
port<1>,,,,
I want to store the elements of each CSV column into an array, but I always get error when I try to fetch those "null" elements in the csv when I run the script. Here's my code:
# ... assuming file was correctly opened and stored into
# ... a variable named $map_in
my $counter = 0;
while($map_in){
chomp;
#hold_csv = split(',',$_);
$entry1[$counter] = $hold_csv[0];
$entry2[$counter] = $hold_csv[1];
$entry3[$counter] = $hold_csv[2];
$entry4[$counter] = $hold_csv[3];
$counter++;
}
print "$entry1[0]\n$entry2[0]\n$entry3[0]\n$entry3[0]"; #test printing
I always got use of uninitialized value error whenever i fetch empty CSV cells
Can you help me locate the error in my code ('cause I know I have somewhat missed something on my code)?
Thanks.
This looks like CSV. So the tool for the job is really Text::CSV.
I will also suggest - having 4 different arrays with numbered names says to me that you're probably wanting a multi-dimensional data structure in the first place.
So I'd be doing something like:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Text::CSV;
my $csv = Text::CSV->new( { binary => 1 } );
open( my $input, "<", "input.csv" ) or die $!;
my #results;
while ( my $row = $csv->getline($input) ) {
push ( #results, \#$row );
}
print join ( ",", #{$results[0]} ),"\n";
print Dumper \#results;
close($input);
If you really want separate arrays, I'd suggest naming them something different, but you could do it like this:
push ( #array1, $$row[0] ); #note - double $, because we dereference
I will note - there's an error in your code - I doubt:
while($map_in){
is doing what you think it is.
When you're assigning $entryN, define a default value:
$entry1[$counter] = $hold_csv[0] || '';
same for other #entry
I think there is a typo in while($map_in) { it should be while (#map_in) {.

Perl matching multidimensional array elements

Im not getting any output, anyone get where the issue lies,
matching or calling?
(The two subarrays in the multidimensional array have the same length.)
//Multidimensional array,
//Idarray = Fasta ID, Seqarray = "ATTGTTGGT" sequences
#ordarray = (\#idarray, \#seqarray);
//This calling works
print $ordarray[0][0] , "\n";
print $ordarray[1][0] , "\n", "\n";
// Ordarray output = "TTGTGGCACATAATTTGTTTAATCCAGAT....."
User inputs a search string, loop iterates the sequence dimension,
and counts amount of matches. Prints number of matches and the corresponding ID from the ID dimension.
//The user input-searchstring
$sestri = <>;
for($r=0;$r<#idarray;$r++) {
if ($sestri =~ $ordarray[1][$r] ){
print $ordarray[0][$r] , "\n";
$counts = () = $ordarray[0][$r] =~ /$sestri/g;
print "number of counts: ", $counts ;
}
I think the problem lies with this:
$sestri = <>;
That may well not be doing what you intended - your comment says "user specified search string" but that's not what that operator does.
What it does, is open the filename you specifed on the command line, and 'return' the first line.
I would suggest that if you want to grab a search string from command line you want to do it via #ARGV
E.g.
my ( $sestri ) = #ARGV; # will give first word.
However, please please please switch on use strict and use warnings. You should always do this prior to posting on a forum for assistance.
I would also question quite why you need a two dimensional array with two elements in it though. It seems unnecessary.
Why not instead make a hash, and key your "fasta ids" to the sequence?
E.g.
my %id_of;
#id_of{#seqarray} = #idarray;
my %seq_of;
#seq_of{#id_array} = #seqarray;
I think this would suit your code a bit better, because then you don't have to worry about the array indicies at all.
use strict;
use warnings;
my ($sestri) = #ARGV;
my %id_of;
#id_of{#seqarray} = #idarray;
foreach my $sequence ( keys %id_of ) {
##NB - this is a pattern match, and will be 'true'
## if $sestri is a substring of $sequence
if ( $sequence =~ m/$sestri/ ) {
print $id_of{$sequence}, "\n";
my $count = () = $sequence =~ m/$sestri/g;
print "number of counts: ", $count, "\n";
}
}
I've rewritten it a bit, because I'm not entirely understanding what your code is doing. It looks like it's substring matching in #seqarray but then returning the count of matching elements in #idarray I don't think that makes sense, but if it does, then amend according to your needs.

Looping through 2D array in Perl?

If I have a 2D array, how can it be possible to access an entire subarray inside of loop? Right now I have
foreach my $row(#data){
foreach my $ind(#$row){
#perform operations on specific index
}
}
but ideally I'm looking for something along the lines of
foreach my $row(#data){
#read row data like $row[0], which if it has the data I'm looking for
#I can go ahead and access $row[3] while in the same row..
}
I'm fairly new to Perl so might just not understand something yet, but I keep "Global symbol "#row" requires explicit package name" when trying to use it the way I want to.
You're close. $row is an array reference and you access its elements with the deference operator ->[...]:
foreach my $row (#data) {
if ($row->[0] == 42) { ... }
$row[0] refers to an element of the array variable #row, which is a completely different (and probably undefined -- thus the Global symbol ... error message) variable than $row.
If $row in your code sample is supposed to be a sub-array, or an array reference, you will have to use the indirect notation to access its elements, like $row->[0], $row->[1], etc.
The reason for your error is because $row[0] actually implies the existence of an array #row, which is probably not present in your script.
You could also try this...
my #ary = ( [12,13,14,15],
[57,58,59,60,61,101],
[67,68,69],
[77,78,79,80,81,301,302,303]);
for (my $f = 0 ; $f < #ary ; $f++) {
for (my $s = 0 ; $s < #{$ary[$f]} ; $s++ ) {
print "$f , $s , $ary[$f][$s]\n";
}
print "\n";
}

Resources