cant retrieve values from hash reversal (Perl) - perl

I've initialized a hash with Names and their class ranking as follows
a=>5,b=>2,c=>1,d=>3,e=>5
I've this code so far
my %Ranks = reverse %Class; #As I need to find out who's ranked first
print "\nFirst place goes to.... ", $Ranks{1};
The code only prints out
"First place goes to...."
I want it to print out
First place goes to....c
Could you tell me where' I'm going wrong here?
The class hash prints correctly
but If I try to print the reversed hash using
foreach $t (keys %Ranks) {
print "\n $t $Ranks{$t}"; }
It prints
5
abc23
cab2
ord
If this helps in any way
FULL CODE
#Script to read from the data file and initialize it into a hash
my %Code;
my %Ranks;
#Check whether the file exists
open(fh, "Task1.txt") or die "The File Does Not Exist!\n", $!;
while (my $line = <fh>) {
chomp $line;
my #fields = split /,/, $line;
$Code{$fields[0]} = $fields[1];
$Class{$fields[0]} = $fields[2];
}
close(fh);
#Prints the dataset
print "Code \t Name\n";
foreach $code ( keys %Code) {
print "$code \t $Code{$code}\n";
}
#Find out who comes first
my %Ranks = reverse %Class;
foreach $t (keys %Ranks)
{
print "\n $t $Ranks{$t}";
}
print "\nFirst place goes to.... ", $Ranks{1}, "\n";

When you want to check what your data structures actually contain, use Data::Dumper. use Data::Dumper; local $Data::Dumper::Useqq = 1; print(Dumper(\%Class));. You'll find un-chomped newlines.

You need to use chomp. At present your $fields[2] value has a trailing newline.
Change your file read loop to this
while (my $line = <fh>) {
chomp $line;
my #fields = split /,/, $line;
$Code{$fields[0]} = $fields[1];
$Class{$fields[0]} = $fields[2];
}

Related

how to count the specific word inputted in STDIN inside the text (PERL)

how to count the specific word inputted in STDIN inside the text (PERL)
my output just count all the owrds found inside the text . but i need the specific word i inputted inside the STDIN
open my($file), '<','C:\Users\yukari\Desktop\hi.txt' or die "not exist";
print "Search the word:";
$word = <STDIN>;
print "\n";
while ( my $line = <$file> ) {
chomp($line);
# print $line;
foreach $word (split(' ', $line)) {
$count{$word}++;
}
}
foreach $word (sort keys %count) {
print "$word: $count{$word}\n";
}
I believe you want to get a word from the user and count the number of occurrences of that word in the entire text file.
You can try something like this:
use strict;
use warnings;
open(WRITE,'>','log.txt') or die "Unable to open the file";
my $string = <<END;
foo baz bar
baz bar bar foo
foo foo bar bar baz baz
baz baz baz
END
print WRITE $string;
close WRITE;
open(READ, '<','log.txt') or die "unable to open the file";
my $search = <STDIN>;
chomp $search;
my $count = 0;
while ( my $line = <READ> ) {
chomp($line);
my #words = split(' ',$line);
foreach my $word(#words){
$count++ if($word eq $search);
}
}
close READ;
print "Search string: $search, Count: $count","\n";
You have a problem here. You are using the variable $word for three different things.
You are using it as the word that you are searching for:
$word = <STDIN>;
You are using it to store each word on a line read from your file:
foreach $word (split(' ', $line)) {
And you are using it to contain the keys you are reading from your hash at the end.
foreach $word (sort keys %count) {
In particular, the second use is interfering with the first. When you are reading data from your file, you have no way of knowing what word you are looking for.
If you are looking for a single word, there is no need for a hash to store the counts. I'd write your code like this:
# ALWAYS INCLUDE THESE
use strict;
use warnings;
use feature 'say';
# Renamed your variable, it's a file handle, not a file.
# Also, include $! in error message so we know what really
# went wrong.
open my $fh, '<', 'C:\Users\yukari\Desktop\hi.txt'
or die "Can't open file: $!";
print "Search the word:";
my $search_word = <STDIN>;
print "\n";
# Scalar variable to store the count
my $count;
# Remove the $line variable and use Perl's default variable $_
# instead. This makes the code *far* cleaner.
while ( <$file> ) {
chomp;
# By default, split splits $_ on whitespace
foreach $word (split) {
# Skip words we don't care about
next if $word ne $search_word;
# Increment the counter
$count++;
}
}
say "$search_word appeared $word times";

How to push an array into nested hash

Does anybody can explain that how can i push array into nested hash. suppose I create a nested hash and want to push an array into key which is a value of another key and also how to access those values of array. pardon me, If i am technically wrong in explaining my query.
Here is part of my code:
if ($line !~ /#/)
{
#region = split /\t/, $line;
#ancestor = split /:/, $region[8];
my #div = split /\s/, $ancestor[0];
push #value, {$region[3],$region[4]};
#print "$region[3],$region[4]\n";
push #{$hash{$div[1]}{$region[0]}},$region[3],$region[4];
}
Here is the code to create the multidimensional hash.
my $filename = 'out.txt';
my %hash = ();
open(my $fh, $filename) or die "Could not open file '$filename' $!";
while (my $line = <$fh>) {
chomp $row;
if ($line !~ /#/)
{
#region = split /\t/, $line;
$len = scalar #region;
if($len >8){
#ancestor = split /:/, $region[8];
my #div = split /\s/, $ancestor[0];
push #value, {$region[3],$region[4]};
push #{$hash{$div[1]}{$region[0]}},[$region[3],$region[4]];
}
}
}
Now to access the hash you can use the below code:
for my $key1 (keys %hash) {
print("Hello $key1");
for my $key2 (keys %{$hash{$key1}}){
print("\t$key2\n");
#res = #{$hash{$key1}{$key2}};
foreach my $arr(#res){
print("\t\t");
print join(",", #{$arr}), "\n";
}
}
print("\n");
}
Hope the above code will work for you.If you need any further help, let me know in comments.
Use square brackets for anonymous arrays. Use curly braces for anonymous hashes.
push #value, [ $region[3], $region[4] ];
push #{$hash{$div[1]}{$region[0]}}, [ $region[3], $region[4] ];

User defined search of a hash

New to Perl. Using Windows 10 w/ Padre IDE. I have a question that has been stumping me and it's probably very simple yet I have yet to find an answer on the net.
Here is the code that is working up until my search. It reads a list.txt file with names and matching phone numbers so I have two hashes (one is name => number, the second is number =>).
my $search = "";
print "File name to be read in: ";
my $textFile = <>;
open FILE, $textFile;
my %hash;
while (<FILE>)
{
chomp;
my ($key, $val) = split / /;
$hash{$key} .= exists $hash{$key} ? "$val" : $val;
}
close FILE;
open FILE, $textFile;
my %hash2;
while (<FILE>)
{
chomp;
my ($val, $key) = split / /;
$hash2{$key} .= exists $hash2{$key} ? "$val" : $val;
}
close FILE;
print "(N) for name (#) for number search and (.) to exit: ";
$search = <>;
if ($search == "N") #heres where we have the problem
{
print "Enter name: ";
my $person = <>; #user defined search looks for Bob Smith
print $hash{$person}; #prints nothing
}
However, when I make the search non-user defined, it works perfected as in:
if ($search == "N")
{
#print "Enter name: ";
#my $person = <>;
print $hash{"Bob Smith"}; #prints Bob Smith's number
}
For the record, I had $search print to screen to verify that there was no issue whenI entered the name in the first place. When I user-define the search, the hash will not pull up. When the name is specically coded into the hash function, it works every time.
Thank you for helping a stumped Perl Noobie.
You have a trailing newline character. You need to chomp before you compare:
$search = <>;
chomp $search;
Also, you should use the string compare eq:
if ($search eq "N")

Counting and printing location of duplicate words in a line using Perl

I am trying to read from a file and print out the location of duplicate words on each line.I have stored each line in an array, but I am not sure if this is the right way to start.
while (my $fileLine = <$fh>){
my #lineWords = split /\s+/, $fileLine;
print "#\n"
}
#!/usr/bin/perl
use strict;
use warnings;
while (<DATA>){
chomp; # remove end of line chars
my #wordsInLine = split /\s+/, $_;
#wordsInLine = map {lc($_)} #wordsInLine; # convert words to lowercase
my( $word, %wordsInLine, $n );
for $word (#wordsInLine) {
$wordsInLine{$word}++; # use hash %wordsInLine to count occurences of words
}
for $word (#wordsInLine) {
$n++;
if( (my $count = $wordsInLine{$word}||0) > 1 ) {
print "line $.: Word $n \"$word\" is repeated $count times\n";
delete($wordsInLine{$word}); # do not generate more than one report
# about the same word in single line
}
}
}
__DATA__
This this is a sample sentence
A that That THAT !

how to write my results to external file in perl

I am trying to read some particular columns from myu data into my output file, i succeed in this reading one cloumn at a time but i want to read some more columns of my interest at a time (i have list of column i want to extract in a separate tex file) because extract individual column and joining them to make one separate file will become hectic to me, here is the code i tried to extract single coulmn,
#!/usr/bin/perl
use strict;
use warnings;
open (DATA, "<file.txt") or die ("Unable to open file");
my $search_string = "IADC512444";
my $header = <DATA>;
my #header_titles = split /\t/, $header;
my $extract_col = 0;
for my $header_line (#header_titles) {
last if $header_line =~ m/$search_string/;
$extract_col++;
}
print "Extracting column $extract_col\n";
while ( my $row = <DATA> ) {
last unless $row =~ /\S/;
chomp $row;
my #cells = split /\t/, $row;
print "$cells[$extract_col] ";
}
is there any possibility to extract all columns at a time instead of only IADC512444 i want from my textfile into outfile on to my harddisc? please help me in solving this problem,
Thanks
If you need to print the contents to a file on disk then you should open a file in write mode and write to it. Also if you want more columns you can do that by accessing corresponding element in the array cells. In this example i am printing the column you are printing plus column 1 and 2
open(OUT_FILE,">path_to_out_file") || die "cant open file...";
while ( my $row = <DATA> ) {
last unless $row =~ /\S/;
chomp $row;
my #cells = split /\t/, $row;
#print "$cells[$extract_col] ";
print OUT_FILE "$cells[$extract_col],$cells[1],$cells[2]\n";
}
close(OUT_FILE)
I have tweaked the code little bit to suit your requirement.
In the variable req_hdr_string you should say the column names which you require separated by ,
So it will be splitted and stored in a hash.
Then from the header i get the position of the column and print only those
#!/usr/bin/perl
use strict;
use warnings;
open (DATA, "<h11.txt") or die ("Unable to open file");
my $req_hdr_string = "abc,ghi,mno,";
my %req_hdrs = ();
my %extract_col = ();
foreach(split /,/, $req_hdr_string)
{
print "req hdr is:$_\n";
$req_hdrs{$_} = $_;
}
my $index = 0;
my $header = <DATA>;
chomp $header;
foreach (split /\t/, $header)
{
print "input is:|$_|\n";
if(exists $req_hdrs{$_})
{
print "\treq index is:$index\n";
$extract_col{$index} = 1;
}
$index++;
}
open(OUT_FILE,">out_file") || die "cant open file...";
while ( my $row = <DATA> )
{
last unless $row =~ /\S/;
chomp $row;
my #cells = split /\t/, $row;
foreach $index (sort keys%extract_col)
{
print OUT_FILE "$cells[$index],";
}
print OUT_FILE "\n";
}
close(OUT_FILE);
close(DATA);