Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Re: Reversing the action of the while loop

by GrandFather (Saint)
on Nov 24, 2019 at 19:54 UTC ( [id://11109154]=note: print w/replies, xml ) Need Help??


in reply to Reversing the action of the while loop

What is the bigger problem you are trying to solve? Most likely you can do it by reading the file forwards and change your test to suit.

Alternatively, if the file is small (less than say a few hundred megabytes) you could simply read lines into an array then run through the array backwards.

The more you tell us about the big picture problem you are trying to solve the more we are likely to be able to help.

Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
  • Comment on Re: Reversing the action of the while loop

Replies are listed 'Best First'.
Re^2: Reversing the action of the while loop
by Scotmonk (Sexton) on Nov 24, 2019 at 22:18 UTC
    The problem, I feel, is complex but perhaps you guys are more practiced in dealing with computers so it might be easier.

    The difficult part of this is trying to make sense to you guys
    I have lines of data elements in a .vim file (this can vary between 5 data elements per line and 25)
    Each element is distinct from the others, regarded as a different sample

    I have been reading one line of data and comparing it with the previous x number of lines of data, looking for matches in value
    (which I have code for and can provide below)

    I now have to be more specific, in that I have to read the individual data from each line, and eliminating any replication, keep adding new values until I have x amount of values.

    so for example:

    my input data would look something like this

    1 2 6 4 5
    6 7 8 9 10
    1 2 11 12 13
    6 14 15 16 17

    If I chose to read 13 elements of data, i would read
    1 2 6 4 5 6 7 8 9 10 1 2 11

    Now I need to remove duplicate values, in this case one of the 1, one of the 2, and one of the 11 (but values could be triplicated or more)

    so that would result in

    1 2 4 5 6 7 8 9 10 11

    This final line would then be compared with the next complete unread line in the file, with matches printed to one file and nonmatches printed to another as per the code below.

    (so the match file would read)
    6
    (and the nonmatch file would read)
    14 15 16 17

    Now there is actually another step to what I do on paper that I would like the PERL script to perform

    Initially I had chosen 13 values (and this can vary between 5 and upto 80)

    If it is the case that duplicates are removed, I dont have the 13 values that I originally planned for

    so on paper, I continue to read forward until I have my required number of values filled in (without duplicates)

    even if that means reading into more lines of data, and moving forward the line that I will eventually compare with

    Does this make any sense at all ? :)

    thankyou
    my $line = 4; while (@lines > 3) { # check first 3 lines against the 4th line my @vals = split /\s+/, $lines[3]; my @chk = split /\s+/, join(' ', @lines[0..2]); my %match; foreach my $val (@vals) { $match{$val}++ if grep { $val eq $_ } @chk; } my @match = sort keys %match; my @nomatch = grep { not exists $match{$_} } @vals; my $match = @match; my $nomatch = @nomatch; # do whatever you want with the matches and no-matches print MATCH "$line: \tmatch = @match\n"; print NOMATCH "$line: \tnomatch = @nomatch\n"; $line++; # get rid of first line so next loop will be 2-6 and so on shift @lines; }

      Here's my guess at something like what you want. Instead of printing @match and @nomatch at the end, just write their contents to the proper files, and change the input to read from your input file.

      #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11109150 use warnings; my $x = 9; my %uniques; my @match; my @nomatch; while( <DATA> ) { print; for my $element ( split ) { if( keys %uniques < $x ) { $uniques{ $element }++; } else { if( $uniques{ $element } ) { push @match, $element; } else { push @nomatch, $element; } } } } print "\nMATCH:\n@match\n\nNOMATCH:\n@nomatch\n"; __DATA__ 1 2 6 4 5 6 7 8 9 10 1 2 11 12 13 6 14 15 16 17

      Outputs:

      1 2 6 4 5 6 7 8 9 10 1 2 11 12 13 6 14 15 16 17 MATCH: 1 2 6 NOMATCH: 11 12 13 14 15 16 17

      Hi Scotmonk,

      This is a great use-case for using an ordered hash (like a hash but with key insertion order preserved). Fortunately, such a module exists. For this demonstration, I'm more interested in the hash keys, not the hash values (i.e. hash key-driven implementation).

      # https://www.perlmonks.org/?node_id=11109163 use strict; use warnings; use feature 'say'; use Hash::Ordered; tie my %elems, 'Hash::Ordered'; tie my %match, 'Hash::Ordered'; tie my %nomatch, 'Hash::Ordered'; my $skip_duplicates = 0; # set to 1 to skip duplicates my $num_elements = 13; # number of elements to read my $num_read = 0; # number of elements read my @lines = <DATA>; chomp @lines; # read elements while ( @lines && $num_read < $num_elements ) { my $line = shift @lines; foreach my $elem ( split / /, $line ) { if ( $skip_duplicates ) { $num_read++ unless exists $elems{ $elem }; } else { $num_read++; } $elems{ $elem } = undef; last if $num_read == $num_elements; } } say "data elements"; say join(' ', keys %elems); # matched, not matched if ( @lines ) { foreach my $elem ( split / /, shift @lines ) { ( exists $elems{ $elem } ) ? $match{ $elem } = undef : $nomatch{ $elem } = undef; } say "match"; say join(' ', keys %match); say "nomatch"; say join(' ', keys %nomatch); } else { say "no more lines"; } __DATA__ 1 2 6 4 5 6 7 8 9 10 1 2 11 12 13 6 14 15 16 17 2 18 19 20 21

      Output: $skip_duplicates = 0

      data elements 1 2 6 4 5 7 8 9 10 11 match 6 nomatch 14 15 16 17

      Output: $skip_duplicates = 1

      data elements 1 2 6 4 5 7 8 9 10 11 12 13 14 match 2 nomatch 18 19 20 21

      Regards, Mario

        Thankyou Mario

        I get an error on execution
        Can't locate Hash/Ordered.pm in @INC (@INC contains: C:/Dwimperl/perl/site/lib C:/Dwimperl/perl/vendor/lib C:/Dwimperl/perl/lib .) at compare001.pl line 7.

        How can I remedy this ?
        Thankyou
        Michael
        I successfully installed Hash::Ordered
        still gettng this message. Is there something else I should do ?
        Can't locate Hash/Ordered.pm in @INC (@INC contains: C:/Dwimperl/perl/site/lib C:/Dwimperl/perl/vendor/lib C:/Dwimperl/perl/lib .) at compare001.pl line 8. BEGIN failed--compilation aborted at compare001.pl line 8.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (2)
As of 2024-04-16 23:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found