http://qs1969.pair.com?node_id=589194

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

Hello, I am looking for a way to print output to my screen in the reverse order that it sits in my array, BUT, without using the reverse command, like i do in my example. Here is my code, at the moment, for printing output to the screen from a file:
my $input = 'somelist'; # Original Line open(my $in, "<", $input) or die "Could not open $input because $!\n"; my @unsorted = <$in>; chomp (@unsorted); # get rid of end-of-record markers close ($in); my @sorted = sort @unsorted; for (my $i=0; $i <=$#sorted; $i++) { print $sorted [$i], "\n"; } @rocks = reverse(@sorted); foreach $rock (@rocks) { $rock = "\t$rock" ; # \t is a tab $rock .="\n" ; } print "\n"; print "The names, backwards, are:\n", @rocks;
I know I am close, but not sure how to context the issue. It's in the formatting of the "for (my.." line, I think. Isn't it? Any assistance / hints or pointers would be appreciated in this perplexing matter. Thank you.

Replies are listed 'Best First'.
Re: For Loops and Reversing output
by ikegami (Patriarch) on Dec 12, 2006 at 00:33 UTC
    my @sorted = sort @unsorted; for (my $i=$#sorted; $i>=0; $i--) { print $sorted[$i], "\n"; }

    However,
    my @sorted = reverse sort @unsorted;
    is optimized to be just as fast as
    my @sorted = sort @unsorted;
    so you're making your program less readable for nothing by avoiding reverse.

    use strict; use warnings; use Benchmark qw( cmpthese ); use List::Util qw( shuffle ); use constant COUNT => $ARGV[0]; use constant TIME => $ARGV[1]; our @unsorted = shuffle map "$_", 1..COUNT; my $neg_step = ' use strict; use warnings; our @unsorted; my @output; my @sorted = sort @unsorted; for (my $i=$#sorted; $i>=0; $i--) { push(@output, $sorted[$i]); } 1; '; my $neg_i = ' use strict; use warnings; our @unsorted; my @output; my @sorted = sort @unsorted; for my $i (-$#sorted..0) { push(@output, $sorted[$i]); } 1; '; my $b_cmp_a = ' use strict; use warnings; our @unsorted; my @output; my @sorted = sort { $b cmp $a } @unsorted; for my $i (0..$#sorted) { push(@output, $sorted[$i]); } 1; '; my $reversed = ' use strict; use warnings; our @unsorted; my @output; my @sorted = reverse sort @unsorted; for my $i (0..$#sorted) { push(@output, $sorted[$i]); } 1; '; cmpthese(TIME, { neg_step => $neg_step, neg_i => $neg_i, b_cmp_a => $b_cmp_a, reversed => $reversed, });

    outputs

    >perl 589197.pl 1000 -3 Rate neg_step b_cmp_a reversed neg_i neg_step 301/s -- -0% -1% -1% b_cmp_a 302/s 0% -- -1% -1% reversed 304/s 1% 1% -- -0% neg_i 304/s 1% 1% 0% -- >perl 589197.pl 1000 -3 Rate b_cmp_a neg_step reversed neg_i b_cmp_a 301/s -- -1% -2% -2% neg_step 303/s 1% -- -1% -1% reversed 306/s 2% 1% -- -0% neg_i 306/s 2% 1% 0% -- >perl 589197.pl 1000 -3 Rate neg_step b_cmp_a neg_i reversed neg_step 301/s -- -0% -1% -2% b_cmp_a 302/s 0% -- -1% -1% neg_i 305/s 1% 1% -- -0% reversed 306/s 2% 1% 0% -- >perl 589197.pl 10000 -5 Rate b_cmp_a neg_step neg_i reversed b_cmp_a 22.4/s -- -1% -2% -3% neg_step 22.6/s 1% -- -2% -2% neg_i 23.0/s 2% 2% -- -0% reversed 23.0/s 3% 2% 0% -- >perl 589197.pl 10000 -5 Rate neg_step b_cmp_a reversed neg_i neg_step 22.5/s -- -0% -2% -2% b_cmp_a 22.5/s 0% -- -2% -2% reversed 22.9/s 2% 2% -- -0% neg_i 23.0/s 2% 2% 0% -- >perl 589197.pl 10000 -5 Rate b_cmp_a neg_step neg_i reversed b_cmp_a 22.5/s -- -1% -2% -2% neg_step 22.7/s 1% -- -1% -1% neg_i 22.8/s 2% 1% -- -1% reversed 23.0/s 2% 1% 1% --

    As you can see, none is faster than any other, so pick the one that's more readable and maintainable.

    Update: Oops! Changed $i++ to $i--.
    Update: Added benchmarks.

Re: For Loops and Reversing output
by liverpole (Monsignor) on Dec 12, 2006 at 00:42 UTC
    Hi brusimm,

    There are a lot of ways to use an array backwards.

    One is to simply reverse the order of the sort.  For example, instead of

    my @sorted = sort @unsorted;

    which is doing an implicit sort { $a cmp $b } @unsorted, you could do:

    my @sorted = sort { $b cmp $a } @unsorted;

    to have the order reversed at the end of the sort.

    Another way is to read an item one-at-a-time from the end of the list, such as in:

    my $nextitem; while ($nextitem = pop @rocks) { # Use $nextitem }

    (Sorry, I couldn't resist using pop @rocks :-))

    As a 3rd and final example, read one at a time from the end of the array using an index, using the -N notation (which reads from the -Nth value of the array each time):

    for (my $i=1; $i <= @rocks; $i++) { my $nextitem = $rocks[- $i]; # Take the ${i}th item from the en +d }

    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: For Loops and Reversing output
by Joost (Canon) on Dec 12, 2006 at 00:35 UTC
    Please take a little time to format and indent your code properly. This looks like a mess. You can use perltidy if you don't want to do it by hand.

    Also, is there any particular reason you don't want to use the reverse keyword?

    You're right that you need to do something to the "for" line Let's examine that statement a bit more:

    for ( my $i=0; # start with this value of $i $i <=$#sorted; # loop while $i <= $#sorted(the last index in @s +orted) $i++ # increase $i by one after each iteration ) { print "$sorted[$i]\n"; # print element number $i }
    Take a few moments to think and it should be clear how to reverse this loop.
      Also, is there any particular reason you don't want to use the reverse keyword?

      Because that's what the homework assignment he's pawning off on us said?

Re: For Loops and Reversing output
by Limbic~Region (Chancellor) on Dec 12, 2006 at 00:36 UTC
    brusimm,
    So you want to reverse without using reverse:
    my $idx = $#array; while ($idx--) { print "$array[$idx]\n"; }
    Oh, you really want to go forwards but have the output appear backwards?
    my $output = ''; for my $elem (@array) { $output = "$elem\n" . $output; } $output .= "\n"; print $output;

    Cheers - L~R

Re: For Loops and Reversing output
by GrandFather (Saint) on Dec 12, 2006 at 00:40 UTC

    Something like this maybe?

    use strict; use warnings; my $input = 'somelist'; # Original Line my @unsorted = qw(big small knobly broken round green); my @sorted = sort @unsorted; my @rocks; for (@sorted) { unshift @rocks, $_; print "$_\n" } print "\n"; print "The names, backwards, are:\n\t", join "\n\t", @rocks;

    Prints:

    big broken green knobly round small The names, backwards, are: small round knobly green broken big

    DWIM is Perl's answer to Gödel
Re: For Loops and Reversing output
by jonadab (Parson) on Dec 12, 2006 at 14:34 UTC

    Another way to do it, without icky C-style for loops:

    my $input = 'somelist'; open(my $in, "<", $input) or die "Could not open $input because $!\n"; my @sorted = sort map { chomp; "\t$_\n" } <$in>; close ($in); print @sorted; my @rocks; push @rocks, pop @sorted while @sorted; print "\n"; print "The names, backwards, are:\n", @rocks;

    Or another way, that doesn't destroy @sorted in the process:

    my @rocks = sort { $b cmp $a } @sorted;

    Sanity? Oh, yeah, I've got all kinds of sanity. In fact, I've developed whole new kinds of sanity. You can just call me "Mister Sanity". Why, I've got so much sanity it's driving me crazy.
Re: For Loops and Reversing output
by chrism01 (Friar) on Dec 13, 2006 at 05:49 UTC
    I think people thought 'homework', as did I, because not being allowed to use 'reverse' sounds like a completely arbitrary restriction, typical of academic qns designed to force you to learn more about the lang.
    Nothing wrong with that in that env, of course, but definitely unusual in real world.
    I'm guessing that maybe the amt of data involved in the up-coming job is extremely large & using reverse would cause perf/mem issues? Maybe embedded code?
    Cheers
    Chris

      reverse sort uses no more memory than sort.

      I've showed earlier in this thread that reverse sort is just as fast as sort. That's because an optimization causes reverse sort to sort the list in the reverse order rather than sorting the list then reversing it. That also means that reverse sort uses no more memory than sort.

      However, reversing an already sorted list takes more time and memory than not reversing it.

      Based on a reply the OP made, I suspect he will be receiving the list already sorted in the reverse of the desired order. If that's the case, then reversing the list then iterating over it would take time and memory, while iterating over the list from end to start could avoid using time and memory.

      Compare

      my @reversed = reverse @sorted; for my $i (0..$#reversed) { print $reversed[$i], "\n"; }

      against

      for (my $i=$#sorted; $i>=0; $i--) { print $sorted[$i], "\n"; }
Re: For Loops and Reversing output
by brusimm (Pilgrim) on Dec 12, 2006 at 21:24 UTC
    Thanks to everyone and their input.. I like the variety of ways to do this.. some obvious, now that I see them, and others more complicated.. this helps me see different angles to the issue and is much appreciated.

    I'd like to clarify on an issue or two: I do want to use reverse, BUT, I was told that the work I am going into at my new job may need to make use of printing backwards w/o using reverse. (They did not specify why.)

    I am sorry someone feels as if I pawned off my homework assignment. I actually was doing web and book searches for a couple of hours before I decided to post here.. BEING NEW to perl, I wasn't sure what to look for, or search for. Does anyone have suggestions for how to search for stuff, AND I am not meaning, how to use the search pages, but terminology and what not for trying to find what I am looking for?

    Again, thanks.

    SANITY: Sanity is a one trick pony, no other options. Being insane, you have LOTS of options available to you!

Re: For Loops and Reversing output
by Anonymous Monk on Dec 12, 2006 at 09:07 UTC
    Are you looking to print your array in reverse order. If thats the case its easy. just loop in the following way for (my $i=$#sorted; $i>0 ; $i--) { print $sorted $i, "\n"; } Hope this helps
      That should be for (my $i=$#sorted; $i>=0; $i--) (>=0, not >0), and it's the first thing mentioned in the first reply.