Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an array loop indefinitely?

I have a list of names:

@names = qw(John Peter Michael);

I want to take 2 values from it, so I get John and Peter. If I want to take 2 more - I get Michael and John. 1 more - Peter. 3 more - Michael John and Peter, and so on.

I've started writing a subroutine where a global index ID would be set and remembered, and would reset itself to zero once it reaches scalar limit of an array, but then I read somewhere that Perl arrays "remember" the position they were looped.

Is that true or am I misunderstanding something? Is there a way to do my task an easy way?

like image 967
DisplayMyName Avatar asked Aug 01 '26 09:08

DisplayMyName


2 Answers

It's not that hard to roll your own iterator, but perlfaq4 has your need covered:


How do I handle circular lists?

(contributed by brian d foy)

If you want to cycle through an array endlessly, you can increment the index modulo the number of elements in the array:

my @array = qw( a b c );
my $i = 0;
while( 1 ) {
    print $array[ $i++ % @array ], "\n";
    last if $i > 20;
} 

You can also use Tie::Cycle to use a scalar that always has the next element of the circular array:

use Tie::Cycle;
tie my $cycle, 'Tie::Cycle', [ qw( FFFFFF 000000 FFFF00 ) ];
print $cycle; # FFFFFF
print $cycle; # 000000
print $cycle; # FFFF00

The Array::Iterator::Circular creates an iterator object for circular arrays:

use Array::Iterator::Circular;
my $color_iterator = Array::Iterator::Circular->new(
    qw(red green blue orange)
    );
foreach ( 1 .. 20 ) {
    print $color_iterator->next, "\n";
}

The roll-your-own variety

The subroutine is really quite simple (implemented as circularize in the code below). The value of $i is retained in $colors's scope, so no need for state variables:

sub circularize {
  my @array = @_;
  my $i = 0;
  return sub { $array[ $i++ % @array ] }
}

my $colors = circularize( qw( red blue orange purple ) ); # Initialize

print $colors->(), "\n" for 1 .. 14; # Use
like image 162
Zaid Avatar answered Aug 04 '26 02:08

Zaid


I never fully understood that mechanism (is it only on foreach?). I would just use state values, e.g.:

my @names = qw(John Peter Michael);

sub GetNames($) {
  my $count = shift;
  my @result = ();

  state $index = 0;
  state $length = scalar(@names);

  while($count--) {
    push(@result, $names[($index++ % $length)]);
  }
  return @result;
}


print join(", ", GetNames(2)), "\n\n";
print join(", ", GetNames(4)), "\n";

Outputs:

John, Peter

Michael, John, Peter, Michael

like image 21
Kris Oye Avatar answered Aug 04 '26 03:08

Kris Oye



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!