in reply to Need help figuring out how to order/eval the numbers

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:

#! perl #################################################################### # Key 0 1 2 3 4 # Italian => Spanish, French, German, English|German, English|German #################################################################### use strict; use warnings; use autodie; use constant NAMES => qw(uno due tre quattro cinque sei sette otto nou +ve dieci undici dodici tredici); my %hash; open my $in, '<', './Test_Data_RandNumbers.txt'; while (<$in>) { my ($ita, $spa, $ger) = split /[=\s,]+/; if ($ita) { $hash{$ita}[0] = $spa; $hash{$ita}[2] = $ger if $ger; } } close $in; open my $in1, '<', './Test_Data_More_RandNumbers.txt'; while (<$in1>) { # $num1 & $num2 may each be either English or German my ($ita, $fren, $num1, $num2) = split /[=\s,]+/; $hash{$ita}[1] = $fren; if ($num1) { $hash{$ita}[3] = $num1; $hash{$ita}[4] = $num2 if $num2; } } close $in1; open my $out , '>', './OUT_Test_Data_Ita_SpanFren_rest.txt'; open my $out1, '>', './OUT_Test_data_NO_match_SpanFren.txt'; for my $ita (sort { sort_italian() } keys %hash) { if ($ita) { my $fh = defined $hash{$ita}[0] && defined $hash{$ita}[1] ? $out : $out1; print $fh "$ita => ", join(',', map { $_ // () } @{ $hash{$ita} }), "\n"; } } close $out; close $out1; { my %numbers; BEGIN { my $i = 1; %numbers = map { $_ => $i++ } NAMES; } sub sort_italian { # Add error checking here! return $numbers{$a} <=> $numbers{$b}; } }

Some notes:

Hope that helps,

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

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

Replies are listed 'Best First'.
Re^2: Need help figuring out how to order/eval the numbers
by perlynewby (Scribe) on Jun 22, 2015 at 19:29 UTC

    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,

        excellent! I liked the break down of the expression...I totally had some of this wrong in my head

        this explanations were very insightful and removed misconception that I may have had...that's not to say I will get it right on my next try(s) to modify/learn perl code.

        will think of a program to use what I have learn from you...or you can provide me with an idea to utilize these new learnings too...and so expect a little more questions

        again Grazie MILLE

        I am now stopped with my new test to implement new learnings...I read and reviewed other code and still lost...maybe I need a break or think of a better test prog to try out skills

        need help here with doing a proper sub routine check on the values of a hash ref. while using the <=>

        IF the value = value1 then print out to file

        IF value of either is not the same then print those to a file

        1 = 1 2 = 2 3 = 3 4 = 4 5 = 5
        1 = 2 2 = 2 3 = 4 4 = 7 5 = 5 6 = 6
        use strict; use warnings; use autodie; use diagnostics; use Data::Dump qw(dump); my %seen; open my $in,'<','./Test_Data.txt'; while(<$in>){ my ($key,$value)= split /[\s=\s]+/; $seen{$key}[0]=$value; } close $in; #using ONE hashes to check key open my $in1,'<','./Test_Data1.txt'; while(<$in1>){ my ($key,$value)= split /[\s=\s]+/; $seen{$key}[1]=$value if (exists $seen{$key}); } close $in1; #dump \%seen; #section uses as follows: ? conditional to write on different output f +iles #also, 1st sub to written by me... to check the values open my $out,'>','./OUT_test_data_keys_and_sorted_values_match.txt'; open my $out1,'>','./OUT_test_data_No_values_matched.txt'; foreach my $key ( sort { check_values()} keys %seen){ if ($key){ my $fh = defined $seen{$key}[0] && defined $seen{$key}[1] ? $out:$out1; print $fh "$key => ",join(',',@{$seen{$key}}),"\n"; } } close $out; close $out1; #here is first SUBROUTINE checks that value [0] == value[1] #my %number; sub check_values{ for my $key (sort {$a<=>$b} keys %seen){ #don't know how ,where to get valueat [0],value at[1] from??wh +o has the values? what is really (a and b) in, is it $_ or %seen? wha +t am I really evaluating with,is it like this: $seen{$key}[0]=$a or $ +seen{$key}[1]=$b...completely lost... }

      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...

        That's not error checking. His comment meant that you should add error checking there, to make sure the values being compared exist and are numbers, for instance.

        The <=> operator (search for it in perlop) compares two numbers and returns -1 if the left argument is less than the right one, 0 if they are equal, and +1 if the left argument is greater than the right. It's very commonly used in sort routines, since sort then uses those -1/0/+1 return values to decide which of two values should come first. The way sort works (simplistic explanation coming) is by comparing values in the list to each other, two at a time, and swapping them if they're out of order, and continuing until the entire list is sorted. The subroutine or block you provide as the sort routine is what it uses to compare the two values, which are passed to that routine as $a and $b.

        So he's having sort call sort_italian() to do the comparisons, and it uses the <=> operator to compare the values numerically.

        Aaron B.
        Available for small or large Perl jobs and *nix system administration; see my home node.

        for my $ita (sort { sort_italian() } keys %hash) { # loop code goes here }

        Here's what the code above does.

        1. First, keys gets all the keys from the hash, in no particular order, and passes them to its left as a list.
        2. sort then sorts that list based on the comparison found in the subroutine sort_italian(), and passes the now-sorted list of keys to its left.
        3. 'for' points the variable $ita at the first value on that sorted list, and runs the code in the enclosing braces following it (where I've replaced the code with a comment above). After that block is finished, for points $ita at the second item on the list and runs the block again, then runs it with $ita pointed at the third item, and so on until the list is exhausted or a command inside the block stops it (like last, for instance).

        See perlsyn for more info on the for (also known as foreach) operator. See the section "Foreach Loops" there; stay away from the C-style loops described in the "For Loops" section unless you know you need one.

        Aaron B.
        Available for small or large Perl jobs and *nix system administration; see my home node.