perlpal has asked for the wisdom of the Perl Monks concerning the following question:
I am trying to implement logic to devise a cyclic array.
A hypothetical use case is as follows :
array_1 = ("tom","harry","diana","nick","sally","henry")
array_2 = ("play()","eat()","sleep()")
The first element in array_1 calls the first function in array_2 i.e. "tom" calls function "play()".Likewise.
The 4th element in array_1 should backtrack to the first elementof array_2 i.e "nick" calls function "play()".Continue the cycle.
Both arrays can have any number of elements with the condition size of array_1 always > saize of array2.
Imput for the above is appreciated!
Thanks in advance!
Re: Implementing a cyclic array
by GrandFather (Saint) on Jun 19, 2009 at 11:58 UTC
|
You can do that in a bunch of different ways (this is Perl we speak of so of course you can). Simplest would be something like:
use strict;
use warnings;
my @names = qw(tom harry diana nick sally henry);
my @actions = (\&play, \&eat, \&sleep);
for my $index (0 .. $#names) {
$actions[$index % @actions]->($names[$index]);
}
sub play {
print "$_[0] plays\n";
}
sub eat {
print "$_[0] eats\n";
}
sub sleep {
print "$_[0] sleeps\n";
}
Prints:
tom plays
harry eats
diana sleeps
nick plays
sally eats
henry sleeps
True laziness is hard work
| [reply] [d/l] [select] |
Re: Implementing a cyclic array
by citromatik (Curate) on Jun 19, 2009 at 12:39 UTC
|
Tie::Cycle is a simple module that implements cyclic arrays through a tied reference (to the array):
use strict;
use warnings;
use Tie::Cycle;
my @names = qw/tom harry diana nick sally henry/;
tie my $cycle, 'Tie::Cycle', [
sub{print "$_[0] plays\n"},
sub{print "$_[0] eats\n"},
sub{print "$_[0] sleeps\n"}
];
$cycle && $cycle->($_) for (@names);
Prints:
tom plays
harry eats
diana sleeps
nick plays
sally eats
henry sleeps
The last line ($cycle && $cycle->($_) for (@names);) seems a bit odd, but $cycle->($_) doesn't trigger the FETCH sub in the tied scalar (anybody knows why?) and a first call to $cycle is needed.
| [reply] [d/l] [select] |
Re: Implementing a cyclic array
by johngg (Canon) on Jun 19, 2009 at 15:17 UTC
|
use strict;
use warnings;
my @arr1 = qw{ tom harry diana nick sally henry };
my $iterator = do
{
my $idx = -1;
my @actions = (
sub { print qq{$_[ 0 ] plays\n} },
sub { print qq{$_[ 0 ] eats\n} },
sub { print qq{$_[ 0 ] sleeps\n} },
);
sub {
$idx ++;
$idx = 0 if $idx > $#actions;
&{ $actions[ $idx ] };
};
};
$iterator->( $_ ) for @arr1;
The output
tom plays
harry eats
diana sleeps
nick plays
sally eats
henry sleeps
I hope this is of interest.
Update: Changed array @methods to @actions to avoid confusion since this is nothing to do with OO. | [reply] [d/l] [select] |
Re: Implementing a cyclic array
by AnomalousMonk (Archbishop) on Jun 19, 2009 at 14:29 UTC
|
Yet another way to do it would be with the List::MoreUtils each_array or each_arrayref array iterator generator functions.
The only 'problem' with these functions is that they return the empty list at the end of an iteration cycle to indicate that the cycle has finished, then start the cycle over again with the first array element(s). Because you seem to want to cycle continuously, you would need logic to detect and 'step over' the end condition.
If you want to roll your own custom iterator, here's an approach (actually, something like this is probably on CPAN already somewhere, I just haven't looked – also, the excellent and freely downloadable Higher-Order Perl discusses this technique in great detail):
Output:
Update: Added link to MJD's HOP. | [reply] [d/l] [select] |
Re: Implementing a cyclic array
by NetWallah (Canon) on Jun 19, 2009 at 20:52 UTC
|
In the spirit of TIMTOWTDI, I offer this OO approach:
use strict;
use warnings;
my @array_1 = ("tom","harry","diana","nick","sally","henry");
my @obj = map { new Person (name=>$_) } @array_1;
$_->action() for @obj;
#------------------------------
BEGIN{
package Person;
my $actionIndex=0;
my @actions = qw (play eat sleep);
my %actsub;
sub new{
my ($class, %args )= @_;
return bless { ACTION => $actions[$actionIndex++ % scalar @acti
+ons],
%args,
}, $class;
}
sub action{
my $self = shift;
$actsub{ $self->{ACTION} }->($self,@_);
}
# Initialize class ...
for my $actname (@actions){
$actsub{$actname} =
sub {
my $self = shift;
print $self->{name} . " likes to $actname\n";
}
}
1;
}
Which produces:
tom likes to play
harry likes to eat
diana likes to sleep
nick likes to play
sally likes to eat
henry likes to sleep
Potentia vobiscum ! (Si hoc legere scis nimium eruditionis habes)
| [reply] [d/l] [select] |
Re: Implementing a cyclic array
by JavaFan (Canon) on Jun 19, 2009 at 11:48 UTC
|
| [reply] [d/l] |
Re: Implementing a cyclic array
by Anonymous Monk on Jun 19, 2009 at 11:43 UTC
|
Show what you tried (perl code).
| [reply] |
|
the code i've written to map the elements is as follows :
foreach (@array_1)
{
print "$array_2[0] maps to $_\n";
push(@array_2, shift @array_2);
}
| [reply] [d/l] |
|
While many of the other solutions are perhaps a closer fit to your problem, I thought that I would show you a solution that is closer to the code that you tried:
use strict; use warnings;
my @array_1 = ("tom","harry","diana","nick","sally","henry");
my @array_2 = ("play()","eat()","sleep()");
foreach (@array_1)
{
my $action = shift(@array_2);
print "$action maps to $_\n";
push(@array_2, $action);
}
which prints
play() maps to tom
eat() maps to harry
sleep() maps to diana
play() maps to nick
eat() maps to sally
sleep() maps to henry
| [reply] [d/l] |
|
|