I am not able to get any values to store in the array #AA - arrays

It is getting the correct inputs and printing them inside the for loop but when I try to send it to a function module later or if I try to print it outside the for loop it is empty.
What do I need to change?
#!/usr/bin/perl
use lib "."; # This pragma include the current working directory
use Mytools;
$inputfilename = shift #ARGV;
open (INFILE, $inputfilename) or die
("Error reading file $inputfilename: $! \n");
# Storing every line of the input file in array #file_array
while (<INFILE>){
$file_array[ $#file_array + 1 ] = $_;
}
my $protein;
my #AA;
foreach $protein (#file_array)
{
#AA = Mytools::dnaToAA($protein);
print "The main AA\n",#AA;
}
print "The main array",#file_array;
my $header1 = "AA";
my $header2 = "DNA";
Mytools::printreport($header1, $header2, \#AA, \#file_array);

You're overwriting the #AA in every iteration of the foreach loop.
Instead of
#AA = Mytools::dnaToAA($protein);
use
push #AA, Mytools::dnaToAA($protein);
See push.
Next time, try to post runnable code (see mre), i.e. avoid Mytools as they're irrelevant to the problem and make the code impossible to run for anyone else but you.

Related

How to read from file to array

Trying to read from a txt file and have the results be displayed in the message box. I plan on copying and pasting lines of 1000 and deleting them from the array, later in my code. For now I'd like to be able to see that the file can be read into the array and be displayed:
Local $List
FileReadToArray( "C:/Users/Desktop/recent_list.txt", $List [, $iFlags = $FRTA_COUNT [, $sDelimiter = ""] ])
MsgBox( 0, "Listing", $List )
I get an error:
>"C:\Program Files (x86)\AutoIt3\SciTE\..\autoit3.exe" /ErrorStdOut "C:\Users\Documents\Test.au3"
"FileReadToArray" has no other parameters than the file to read! You have used the function call from "_FileReadToArray".
The square brackets in the function line means: This parameters are optional! If you want to use them with the default values, its not required to write them in the function call.
And "FileReadToArray" reads the content of a file into an array. Thats why your call should look like so:
Local $arList = FileReadToArray("C:/Users/Desktop/recent_list.txt")
; to show every line in a MsgBox you must iterate
; through the result array
For $i = 0 To UBound($arList) -1
; MsgBox is not sensefull with hundred of lines in file!
; MsgBox(0, 'Line ' & $i+1, $arList[$i])
; better way - console output
ConsoleWrite('['& $i+1 & '] ' & $arList[$i] & #CRLF)
Next

ref to a hash -> its member array -> this array's member's value. How to elegantly access and test?

I want to use an expression like
#{ %$hashref{'key_name'}[1]
or
%$hashref{'key_name}->[1]
to get - and then test - the second (index = 1) member of an array (reference) held by my hash as its "key_name" 's value. But, I can not.
This code here is correct (it works), but I would have liked to combine the two lines that I have marked into one single, efficient, perl-elegant line.
foreach my $tag ('doit', 'source', 'dest' ) {
my $exists = exists( $$thisSectionConfig{$tag});
my #tempA = %$thisSectionConfig{$tag} ; #this line
my $non0len = (#tempA[1] =~ /\w+/ ); # and this line
if ( !$exists || !$non0len) {
print STDERR "No complete \"$tag\" ... etc ... \n";
# program exit ...
}
I know you (the general 'you') can elegantly combine these two lines. Could someone tell me how I could do this?
This code it testing a section of a config file that has been read into a $thisSectionConfig reference-to-a-hash by Config::Simple. Each config file key=value pair then is (I looked with datadumper) held as a two-member array: [0] is the key, [1] is the value. The $tag 's are configuration settings that must be present in the config file sections being processed by this code snippet.
Thank you for any help.
You should read about Arrow operator(->). I guess you want something like this:
foreach my $tag ('doit', 'source', 'dest') {
if(exists $thisSectionConfig -> {$tag}){
my $non0len = ($thisSectionConfig -> {$tag} -> [1] =~ /(\w+)/) ;
}
else {
print STDERR "No complete \"$tag\" ... etc ... \n";
# program exit ...
}

Perl: Filtering through an Array to Make a New Array

I'm trying to filter an array of a delimited text file in my program. The array from this text file looks like this:
YCL049C 1 511.2465 0 0 MFSK
YCL049C 2 4422.3098 0 0 YLVTASSLFVALT
YCL049C 3 1131.5600 0 0 DFYQVSFVK
YCL049C 4 1911.0213 0 0 SIAPAIVNSSVIFHDVSR
YCL049C 5 774.4059 0 0 GVAMGNVK
..
.
and the code I have for this section of the program is:
my #msfile_filtered;
my $msline;
foreach $msline (#msfile) {
my ($name, $pnum, $m2c, $charge, $missed, $sequence) = split (" ", $msline);
if (defined $amino) {
if ($amino =~ /$sequence/i) {
push (#msfile_filtered, $msline);
}
}
else {
push (#msfile_filtered, $msline);
}
}
$amino will just be a letter that will be input by the user, and corresponds to the last field $sequence. It is not essential that the user actually inputs $amino, so I need to duplicate this array and keep it unchanged if this is the case (hence the else statement). At the minute the #msfile_filtered array is empty, but I am unsure why, any ideas?
EDIT: just to clarify, there is only one space between each field, I copy and pasted this from notpad++, so extra spaced were added. The file itself will only have one space between fields.
Thanks in advance!
The regex that tries to find matching rows is backwards. To find a needle in a haystack, you need to write $haystack =~ /needle/, not the other way around.
Also, to simplify your logic, if $amino is undef, skip the loop entirely. I would rewrite your code as follows:
if (defined $amino)
{
foreach $msline (#msfile)
{
my ($name, $pnum, $m2c, $charge, $missed, $sequence) = split(" ", $msline);
push #msfile_filtered, $msline if ($sequence =~ /$amino/i);
}
} else
{
#msfile_filtered = #msfile;
}
You could simplify this further down to a single grep statement, but that begins to get hard to read. An example of such a line might be:
#msfile_filtered =
defined $amino
? grep { ( split(" ", $_ ) )[5] =~ /$amino/i } #msfile
: #msfile;
The split is should take more than one whitespaces, and the regex vars are vice versa.
First debug to check that values are correct after the split.
Also, you must swap your regex variables like this:
if ($sequence =~ /$amino/i) {
Now you're checking if $amino contains $sequence, which obviously it doesn't

Morse Code Decoder in Perl

I am trying to teach myself Perl and I have been struggling... Last night I did a program to calculate the average of a set of numbers that the user provided in order to learn about lists and user input so today I thought I would do a Morse Code decoder to learn about Hashes. I have looked through the book that I bought and it doesn't really explain hashes very well... it actually doesn't explain a lot of things very well. Any help would be appreciated!
Anyways, I am wanting to write a program that decodes the morse code that the user inputs. So the user would enter:
-.-.
.-
-
...
!
.-.
..-
.-..
.
The exclamation point would signify a separate word. This message would return "Cats Rule" to the user. Below is the code I have so far... Remember.. I have been programming in perl for under 24 hours haha.
Code:
use 5.010;
my %morsecode=(
'.-' =>'A', '-...' =>'B', '-.-.' =>'C', '-..' =>'D',
'.' =>'E', '..-.' =>'F', '--.' =>'G', '....' =>'H',
'..' =>'I', '.---' =>'J', '-.-' =>'K', '.-..' =>'L',
'--' =>'M', '-.' =>'N', '---' =>'O', '.--.' =>'P',
'--.-' =>'Q', '.-.' =>'R', '...' =>'S', '-' =>'T',
'..-' =>'U', '...-' =>'V', '.--' =>'W', '-..-' =>'X',
'-.--' =>'Y', '--..' =>'Z', '.----' =>'1', '..---' =>'2',
'...--' =>'3', '....-' =>'4', '.....' =>'5', '-....' =>'6',
'--...' =>'7', '---..' =>'8', '----.' =>'9', '-----' =>'0',
'.-.-.-'=>'.', '--..--'=>',', '---...'=>':', '..--..'=>'?',
'.----.'=>'\'', '-...-' =>'-', '-..-.' =>'/', '.-..-.'=>'\"'
);
my #k = keys %morsecode;
my #v = values %morsecode;
say "Enter a message in morse code separated by a line. Use the exclamation point (!) to separate words. Hit Control+D to signal the end of input.";
my #message = <STDIN>;
chomp #message;
my $decodedMessage = encode(#message);
sub encode {
foreach #_ {
if (#_ == #k) {
return #k;
#This is where I am confused... I am going to have to add the values to an array, but I don't really know how to go about it.
}
else if(#_ == '!') {return ' '}
else
{
return 'Input is not valid';
}
}
}
Your code contains two syntactic errors: foreach requires a list to iterate over; this means parens. Unlike C and other languages, Perl doesn't support else if (...). Instead, use elsif (...).
Then there are a few semantic mistakes: The current value of an iteration is stored in $_. The array #_ contains the arguments of the call to your function.
Perl comparse strings and numbers differently:
Strings Numbers
eq ==
lt <
gt >
le <=
ge >=
ne !=
cmp <=>
Use the correct operators for the task at hand, in this case, the stringy ones.
(Your code #_ == #k does something, namely using arrays in numeric context. This produces the number of elements, which is subsequenty compared. #_ == '!' is just weird.)
What you really want to do is to map the inputted values to a list of characters. Your hash defines this mapping, but we want to apply it. Perl has a map function, it works like
#out_list = map { ACTION } #in_list;
Inside the action block, the current value is available as $_.
We want our action to look up the appropriate value in the hash, or include an error message if there is no mapping for the input string:
my #letters = map { $morsecode{$_} // "<unknown code $_>" } #message;
This assumes ! is registered as a space in the morsecode hash.
We then make a single string of these letters by joining them with the empty string:
my $translated_message = join "", #letters;
And don't forget to print out the result!
The complete code:
#!/usr/bin/perl
use strict; use warnings; use 5.012;
my %morsecode=(
'.-' =>'A', '-...' =>'B', '-.-.' =>'C', '-..' =>'D',
'.' =>'E', '..-.' =>'F', '--.' =>'G', '....' =>'H',
'..' =>'I', '.---' =>'J', '-.-' =>'K', '.-..' =>'L',
'--' =>'M', '-.' =>'N', '---' =>'O', '.--.' =>'P',
'--.-' =>'Q', '.-.' =>'R', '...' =>'S', '-' =>'T',
'..-' =>'U', '...-' =>'V', '.--' =>'W', '-..-' =>'X',
'-.--' =>'Y', '--..' =>'Z', '.----' =>'1', '..---' =>'2',
'...--' =>'3', '....-' =>'4', '.....' =>'5', '-....' =>'6',
'--...' =>'7', '---..' =>'8', '----.' =>'9', '-----' =>'0',
'.-.-.-'=>'.', '--..--'=>',', '---...'=>':', '..--..'=>'?',
'.----.'=>'\'', '-...-' =>'-', '-..-.' =>'/', '.-..-.'=>'"',
'!' =>' ',
);
say "Please type in your morse message:";
my #codes = <>;
chomp #codes;
my $message = join "", map { $morsecode{$_} // "<unknown code $_>" } #codes;
say "You said:";
say $message;
This produces the desired output.
There's a lot of value in learning the how and why, but here's the what:
sub encode {
my $output;
foreach my $symbol (#_) {
my $letter = $morsecode{$symbol};
die "Don't know how to decode $symbol" unless defined $letter;
$output .= $letter
}
return $output;
}
or even as little as sub encode { join '', map $morsecode{$_}, #_ } if you're not too worried about error-checking. #k and #v aren't needed for anything.
Searching for values in hashes is a very intense job, you are better of by just using a reverse hash. You can easily reverse a hash with the reverse function in Perl. Also, while watching your code I have seen that you will be able to enter lower-case input. But while searching in hashes on keys, this is case-sensitive. So you will need to uppercase your input. Also, I do not really like the way to "end" an STDIN. An exit word/sign would be better and cleaner.
My take on your code
my %morsecode=(
'.-' =>'A', '-...' =>'B', '-.-.' =>'C', '-..' =>'D',
'.' =>'E', '..-.' =>'F', '--.' =>'G', '....' =>'H',
'..' =>'I', '.---' =>'J', '-.-' =>'K', '.-..' =>'L',
'--' =>'M', '-.' =>'N', '---' =>'O', '.--.' =>'P',
'--.-' =>'Q', '.-.' =>'R', '...' =>'S', '-' =>'T',
'..-' =>'U', '...-' =>'V', '.--' =>'W', '-..-' =>'X',
'-.--' =>'Y', '--..' =>'Z', '.----' =>'1', '..---' =>'2',
'...--' =>'3', '....-' =>'4', '.....' =>'5', '-....' =>'6',
'--...' =>'7', '---..' =>'8', '----.' =>'9', '-----' =>'0',
'.-.-.-'=>'.', '--..--'=>',', '---...'=>':', '..--..'=>'?',
'.----.'=>'\'', '-...-' =>'-', '-..-.' =>'/', '.-..-.'=>'\"'
);
my %reversemorse = reverse %morsecode;
print "Enter a message\n";
chomp (my $message = <STDIN>);
print &encode($message);
sub encode{
my $origmsg = shift(#_);
my #letters = split('',$origmsg);
my $morse = '';
foreach $l(#letters)
{
$morse .= $reversemorse{uc($l)}." ";
}
return $morse;
}

Array not being overwritten

This is a loop and the array does not get overwritten, it just grows.
for ( $j=0; $j <=$#just_ecps ; $j++){
print "$just_ecps[$j]\n";
for ($x=0; $x<=$#folder_dates ; $x++){
my $archivo_histo = "/home/ha2_d11/data/ibprod/archive/$folder_dates[$x]/$just_ecps[$j]/ghistogram.gz";
next unless (-r $archivo_histo);
open(FILEHANDLE, "gunzip -c $archivo_histo |") or die ("could not open file $archivo_histo");
while (<FILEHANDLE>) {
if ($_ =~ /ave:\s+(\d+\.\d+)\s/){
push ( #ecp_average , $1);
sleep 1;
}
print "#ecp_average\n";
}
}
In every instance it is the last three values that are valid, everything before it is a duplicate. I need to get rid of the duplicates and just keep the last three values.
Eislnd1
0.00420743 0.00414601 0.0044511
Eislnd2
0.00420743 0.00414601 0.0044511 0.00303575 0.00309721 0.00302753
Eislnd3
0.00420743 0.00414601 0.0044511 0.00303575 0.00309721 0.00302753 0.0031753 0.00324729 0.00295381
Eislnd4
0.00420743 0.00414601 0.0044511 0.00303575 0.00309721 0.00302753 0.0031753 0.00324729 0.00295381 0.00324191 0.00344244 0.00311481
You need to clear the array for every file:
open(FILEHANDLE, "gunzip -c $archivo_histo |") or die ...
#ecp_average = ();
while (<FILEHANDLE>) {
...
}
At some point you'll want to read up on lexically-scoped variables (i.e. the my declaration)
but for now this should work.
Things to note that will help improve this code:
use strict; use warnings;
Consider using for my $just_ecp ( #just_ecps ) { ... } instead of the C-style construct
Defining an averaging subroutine ( sub avg { sum(#_) / #_ } ) and using it ( avg( #ecp ) ) is a more intuitive way to compute averages instead of mucking around with array lengths. All it takes one line!

Resources