Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Need help figuring out how to order/eval the numbers

by perlynewby (Scribe)
on Jun 21, 2015 at 21:51 UTC ( [id://1131416]=perlquestion: print w/replies, xml ) Need Help??

perlynewby has asked for the wisdom of the Perl Monks concerning the following question:

Good Afternoon Monks, I have come to a hard stop because I cannot figure out how to order these numbers in order from least to greater...

my little program checks between 2 files that contain numbers in different languages then matches those that are found in both then prints them. otherwise, it dumps them into another where the key wasn't found in either.

But now, I wanted to order the output in numerical order(learning perl still so I build on this stuff)

Experiment 1suppose the input file (contains the keys) have the numbers in numerical order. I've been thinking of taking the line number they are found then attach this to the hash somehow...But I don't know how. Any help/advice/hints will be helpful.

Experiment 2the input file does NOT contain the numbers in any order. I suppose I need to check the keys in the hash against to some table to cross check the order of keys before outputting. I don't know how to do this either. hints on how to do this?

Ordered numbers (later will be scrambled)

uno = uno due = dos,zwei tre = tres,drei quattro = quatro cinque = cinco,funf sei = seis, sette = siete,sechs otto = ocho nouve = nueve, neun dieci = diez, zehn undici = once, elf dodici = doce tredici = trece, dreizehn

2nd file

uno = un, one due =deux, two, tre = trois,drei, three quattro = quatre,four cinque = cinq,funf, five sei = six , six sette = sept , seven ,sechs dieci =dix undici = onze,eleven tredici = treize,thirteen, dreizehn

Program

use strict; use diagnostics; use warnings; use autodie qw(open close); use Data::Dump qw(dump); #declare variables my %hash; my $data; #opening Files using autodie to cut typing... open my $in, '<',"./Test_Data_RandNumbers.txt"; open my $in1,'<',"./Test_Data_More_RandNumbers.txt"; open my $out ,'>' ,"./OUT_Test_Data_Ita_SpanFren_rest.txt"; open my $out1,'>',"./OUT_Test_data_NO_match_SpanFren.txt"; while (<$in>){ #data manipulation to clean up ='s and ,'s #dieci = diez, zehn -->worse case, remove spaces and = and comm +a; #quattro = quatro -->only one number with spaces or not in from of + =... chomp; my ($ita,$spa,$num)= split(/[=\s,]+/); # removes '=' or 's' or ',' + & '+' to match 1 or more these characters $hash{$ita}[0]=$spa; #what about if there is no $num at position 1 in 1st file? if (defined $num){ $hash{$ita}[2]=$num; # if defined then keep it for check l +ater in position 2 in array } } close $in; while (<$in1>){ chomp; my ($ita,$fren,$num1,$num2)= split(/[=\s,]+/); #creates col of num +bers $hash{$ita}[1]=$fren; #now hashs format will look like this: ita=> + spa fren #define if there is are numbers in position 3 and 4 concat to posi +tion 3 if (defined ($num1) and defined ($num2)){ $hash{$ita}[3]=$num1.$num2; # concat if numbers defined in poitio +n 1 and 2 and store in 3 } elsif(defined $num1) { $hash{$ita}[3]=$num1; #if array has num in pos 2 then sa +ve number in position 3(dieci) } } close $in1; foreach my $ita (keys %hash){ if($hash{$ita}[0] and $hash{$ita}[1]){ print $out "$ita =>", join(',',@{$hash{$ita}}),"\n"; }else { print $out1 "$ita =>",join(',',@{$hash{$ita}}),"\n"; } } close $out; close $out1;

Replies are listed 'Best First'.
Re: Need help figuring out how to order/eval the numbers
by Athanasius (Archbishop) on Jun 22, 2015 at 08:19 UTC

    Hello perlynewby,

    Since the input data will “later be scrambled,” there doesn’t seem to be much point in pursuing the strategy of Experiment 1. I have therefore looked only at Experiment 2, using a hash for lookup. The resulting code is far from perfect, but it produces the desired output:

    Some notes:

    • I have moved the file open and close statements to reflect the actual usage of the filehandles. It is generally a good idea to minimise a variable’s effective scope.

    • I have added tests such as:

      if ($ita)

      to exclude undefs and null strings from the hash. These tests should really be more explicit:

      if (defined $ita && $ita ne '')

      but the shortcut is OK since neither 0 nor '0' is going to occur in the data as a valid value.

    • In the line

      join(',', map { $_ // () } @{ $hash{$ita} }),

      the map removes undef fields which otherwise produce warnings such as this:

      Use of uninitialized value in join or string at ... line ...
    • The hash keys are sorted using a special-purpose sub, which in turn uses a hash that maps each Italian number name to its corresponding numerical value. See sort for other syntax options.

    • The two chomps are not needed as each is effectively performed by the immediately-following split on whitespace (\s).

    Hope that helps,

    Updates: Made minor improvements to code and text; added final note.

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      thank you...I will follow the FH open and close within their scope...I liked that and clear to me now and looks elegant.also, I like your way of IF structures...mine still looks too childish

      I have a few question on somethings you did here, please help me understand. I am reading on this now too.

      what is the ? do here?

      my $fh = defined $hash{$ita}[0] && defined $hash{$ita}[1] ? $out : $out1;

      hmm, what is in the sort_italian() at start? and why () and not square brackets?

      confused on hash_ref which uses square and now parenthesis

      for my $ita (sort { sort_italian() } keys %hash)

      map...nice function, I'm geeking out on map right now. but what is the () mean? is this NOT a hash_ref then??as per your comment, $_ is the value of the keys being check for UNDEF values , I understand that but not ()

      print $fh "$ita => ", join(',', map { $_ // () } @{ $hash{$ita} }), "\n";

      I have problems following the error checking. what is this statement saying here?         return $numbers{$a} <=> $numbers{$b};

        Hello again perlynewby,

        It seems that, between aaron_baugher’s excellent replies and your own further reading, you already have answers to most of your questions. I will just comment on this part of my code:

        my $fh = defined $hash{$ita}[0] && defined $hash{$ita}[1] ? $out : $out1; print $fh "$ita => ", join(',', map { $_ // () } @{ $hash{$ita} }), "\n";

        The ... ? ... : ... construct is the conditional, or ternary, operator, which is documented here. I use it to select which of two filehandles will be written to by the following print statement. This is an example of applying the DRY (“don’t repeat yourself”) principle by changing the original two parallel print statements into a single statement. The advantage here is that if the statement is later changed (see below!), there is no danger of updating one statement and overlooking the other in the process.

        The expression { $_ // () } uses the Logical Defined-Or operator to select the empty parentheses — () — only if the current value ($_) is undefined. Empty parentheses are used because they represent an empty list, and interpolating an empty list into a second list has no effect on that second list. Any other value here — e.g. undef, "" (the empty string), [] (which is a reference to an empty anonymous array) — would add something unwanted to the second list, because in each case the value is a scalar which is added as a new list element. The following should make this a little clearer:

        17:42 >perl -MData::Dump -wE "my @c = qw(a e i o u); @c = map { $_ eq +'i' ? undef : $_ } @c; dd \@c;" ["a", "e", undef, "o", "u"] 17:44 >perl -MData::Dump -wE "my @c = qw(a e i o u); @c = map { $_ eq +'i' ? () : $_ } @c; dd \@c;" ["a", "e", "o", "u"] 17:44 >
        map...nice function, I'm geeking out on map right now.

        Yor’re right! Unfortunately, map was the wrong function to use here. :-( I should have used grep:

        print $fh "$ita => ", join(',', grep { defined } @{ $hash{$ita} }), "\n";

        — much more straightforward. D’oh!

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        ok, I read about most of my questions and I think I understand them some but I still have an issue with understanding the error check portion here. don't know what this does

        return $numbers{$a} <=> $numbers{$b}; #I guess it's checking against e +achother...but how? is this a subroutine somewhere in a library/modul +e??

        after reading, this is still a little vague. I have issues understanding when to use the [] vs (). any clarification will be appreciated.

        $hash{$ita}[0]=$spa; #here we assign has_ref $span value address to fi +rst position in array for my $ita (sort { sort_italian() } keys %hash) #here ?? adding value + to array? am I right? not sure...

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1131416]
Approved by kevbot
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (8)
As of 2024-04-23 12:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found