YouHaveaBigEgo YouHaveaBigEgo - 3 months ago 14
Perl Question

Unable to loop back when using natatime

I have a array from which I am taking 7 elements at a time, using the function

natatime
from
List::MoreUtils
. They are all positive integers between 0 and 62 in no specific order and are random.

my @attn_range = (0, 39, 21, 17, 62, 43, 62,
1, 40, 22, 16, 60, 41, 59,
2, 41, 23, 15, 58, 39, 56,
3, 42, 24, 14, 56, 37, 53,
4, 43, 25, 13, 54, 35, 50,
5, 44, 26, 12, 52, 33, 47,
6, 45, 27, 11, 50, 31, 44,
7, 46, 28, 10, 48, 29, 41,
....
62, 23, 33, 45, 62, 39, 59);
our $it = List::MoreUtils::natatime(7, @attn_range);
while (1) {
while (my @vals = $it->()){
for my $i (0 .. $#vals){
print "Port$i: $vals[$i], ";
}
print "\n";
}


However, I was expecting to cycle through back from the top when the end of list is reached, but this method doesn't do that.

Can you help me? I desire to loop back to the top at when the last 7 is read and printed inside my
while (1)
loop.

(in my example I created an array
@attn_range
above, but in reality the values in my array are read from a .csv file and @attn_range array is very large and a multiple of 7. I used
natatime
because i found it to be easy, any way can be adopted to take 7 elements from my array.)

Answer

There is no way to "reset" the iterator returned by natatime: you need to simply create a new iterator each time the outer while is executed

And don't use our unless you have a very good reason to do so

This version of your code should work, but beware that it will run endlessly as it stands because there is no exit from the outer while

while () {

    my $iter = List::MoreUtils::natatime(7, @attn_range);

    while ( my @vals = $iter->() ) {

        for my $i ( 0 .. $#vals ) {
            printf "Port%d: %d, ", $i, $vals[$i];
            ...
        }
    }

    print "\n";
}



Update

Now that I'm back at a proper keyboard I can offer something that I hope is more useful

It's wasteful to create a seven-element iterator over and over again, and I would prefer to copy the data into an array of seven-element arrays

This code shows the idea, and also uses join together with map to produce the output that you describe in your question. Each seven-item chunk is available within the for loop as @$group, and its elements are $group->[0] through to $group->[6]

use strict;
use warnings 'all';
use feature 'say';

my @attn_range = (
      0, 39, 21, 17, 62, 43, 62,
      1, 40, 22, 16, 60, 41, 59,
      2, 41, 23, 15, 58, 39, 56,
      3, 42, 24, 14, 56, 37, 53,
      4, 43, 25, 13, 54, 35, 50,
      5, 44, 26, 12, 52, 33, 47,
      6, 45, 27, 11, 50, 31, 44,
      7, 46, 28, 10, 48, 29, 41,
     62, 23, 33, 45, 62, 39, 59,
);

my @groups;
{
    for ( my $i = 0; $i < @attn_range; $i += 7 ) {
        push @groups, [ @attn_range[ $i .. $i+6 ] ];
    }
}

while () {

    for my $group ( @groups ) {
        say join ', ', map {
            sprintf 'Port%d: %2d', $_, $group->[$_];
        } 0 .. $#$group;
    }

    exit;  # For testing
}