foreach @list ( (1,2), (5,6) ){ ... }

M

Markus Dehmann

Why can't I do the following?

foreach my @set ((1,2),(1000,2000)){


print "@set\n";


}





or





foreach my ($a,$b) ((1,2),(1000,2000)){


print "$a,$b\n";


}





Is there a way to make something like that work? I need two variables in
each loop step.

Thanks!
Markus
 
X

Xicheng Jia

Markus said:
Why can't I do the following?

foreach my @set ((1,2),(1000,2000)){

you might save some time by using a CPAN module(List::MoreUtils). if
you want to know how this module works, read the .pm file and "Higher
Order Perl" by MJ. Domunis. the module author, I think, used exactly
the same method as those in the chapter-4 of this book..

Xicheng
_______________
use warnings;
use strict;

use List::MoreUtils 'natatime';

my @x = (1..10);
my $it = natatime 2, @x;
while (my @set = $it->()) {
print "@set\n";
}
__END__
 
K

Keith Keller

Why can't I do the following?

foreach my @set ((1,2),(1000,2000)){
print "@set\n";
}

or

foreach my ($a,$b) ((1,2),(1000,2000)){
print "$a,$b\n";
}

Because that is not permitted by foreach's syntax.
Is there a way to make something like that work? I need two variables in
each loop step.

TIMTOWTDI, of course:

my %hash=(
1=>'1000',
2=>'2000',
);

foreach my $key (sort keys %hash)
{
print "$key,$hash{$key}\n";
}


I have no doubt that there are easier and more elegant methods. You
might start by more specifically describing the relationship between
your list keys and values.

--keith
 
S

SSS

Markus said:
Why can't I do the following?

foreach my @set ((1,2),(1000,2000)){

print "@set\n";

}




or




foreach my ($a,$b) ((1,2),(1000,2000)){

print "$a,$b\n";

}




Is there a way to make something like that work? I need two variables in
each loop step.

Thanks!
Markus


foreach my $set ([1,2],[1000,2000]){
print "$set->[0],$set->[1]\n";
}
 
M

Mumia W.

Markus said:
Why can't I do the following?

foreach my @set ((1,2),(1000,2000)){

print "@set\n";

}
[...]
Is there a way to make something like that work? I need two variables in
each loop step.

Thanks!
Markus

Generally when you need to group arrays, you use references, but in your
case, you can use a normal flattened array and splice:

use strict;
use warnings;

for my $setref ([1,2], [1000,2000]) {
print "@$setref\n";
}

my @sets = ((1,2), (1000,2000));
# happends to equal (1, 2, 1000, 2000)

while (my ($c,$d) = splice(@sets,0,2)) {
print "$c, $d\n";
}

__END__

BTW, avoid making $a and $b lexical.

HTH
 
M

Mirco Wahab

Thus spoke Mumia W. (on 2006-06-01 06:20):
while (my ($c,$d) = splice(@sets,0,2)) {
print "$c, $d\n";
}

Thanks for this quite nice idiom
(I wasn't aware of it), which can
be generalized to:

my @arr =qw{t h i s i s r e a l l y n i c e};
my $n = 3;

while ( my @set = splice @arr, 0 , $n ) {
print "@set,\n";
}
# prints:
# t h i,
# s i s,
# ...


But I'm still struggling to see *why*
the @arr would iterate and not start
out at #0 again.

Thanks & Regards

Mirco
 
D

Dr.Ruud

Mirco Wahab schreef:
But I'm still struggling to see *why*
the @arr would iterate and not start
out at #0 again.

#!/usr/bin/perl
use strict ;
use warnings ;

my @arr = split '', 'thisisreallynice' ;
my $n = 3 ;
local $" = '-' ;

while ( my @set = splice @arr, 0 , $n ) {
print "<@set>\t[@arr]\n" ;
}
 
M

Mirco Wahab

Thus spoke Mirco Wahab (on 2006-06-01 11:51):
Thus spoke Mumia W. (on 2006-06-01 06:20):
But I'm still struggling to see *why*
the @arr would iterate and not start
out at #0 again.

Aaarrrgh, (did too much c++ lately)
the array is, of course, *gone* ;-)

Sorry.

BTW.: But how would one translate
this to a foreach() loop without
nukeing the array;

I could come up with this,
which is (somehow) very ugly:

my @arr =qw{ t h i s i s u g l y };

for my $set (map{my$o=0,my@o;push @o,[$_->[$o++],$_->[$o++]]while($o<@arr);@o}\@arr) {
print "@$set,\n";
}

# prints:
# t h,
# i s,
# ..

Of course, one would use 'natatime'
from Dominus, but just for edu-
cational purpose ...

Regards

Mirco
 
M

Mumia W.

Mirco said:
Thus spoke Mumia W. (on 2006-06-01 06:20):


Thanks for this quite nice idiom

Sure, no problem.
(I wasn't aware of it), which can
be generalized to:

my @arr =qw{t h i s i s r e a l l y n i c e};
my $n = 3;

while ( my @set = splice @arr, 0 , $n ) {
print "@set,\n";
}
# prints:
# t h i,
# s i s,
# ...


But I'm still struggling to see *why*
the @arr would iterate and not start
out at #0 again.

Thanks & Regards

Mirco

Each call to splice reduces the number of elements in @arr. When the
array is empty, the while loop stops.
 
D

Dr.Ruud

Mirco Wahab schreef:
how would one translate
this to a foreach() loop without
nukeing the array;

I could come up with this,
which is (somehow) very ugly:

my @arr =qw{ t h i s i s u g l y };

for my $set (map{my$o=0,my@o;push
@o,[$_->[$o++],$_->[$o++]]while($o<@arr);@o}\@arr) {
print "@$set,\n"; }

# prints:
# t h,
# i s,
# ..


#!/usr/bin/perl
use strict ;
use warnings ;

sub min { $_[0] < $_[1] ? $_[0] : $_[1] }

my @arr = split '', 'thisisnicetoo' ;
my $n = 2 ;
local ($", $\) = ('_', ",\n") ;

for ( my $i = 0 ; $i < @arr ; $i += $n ) {
print "@arr[ $i .. min($i + $n - 1, $#arr) ]" ;
}

my $i = -1 ;
for (@arr) {
++$i % $n or print "@arr[ $i .. min($i + $n - 1, $#arr) ]" ;
}
 
M

Mumia W.

Mirco said:
[...] how would one translate
this to a foreach() loop without
nukeing the array;
[...]

Yeah, that was ugly :)

I would collect the elements into another array and print that. Here it
is done two ways: one with storing the data and one without storing:

use strict;
use warnings;
use English;
use Data::Dumper;

my @words = split //,'Thisissopretty.';
my $size = 3;
my $loc = 0;
my @groups;

foreach my $let (@words) {
push @{ $groups[$loc] }, $let;
if (@{ $groups[$loc] } >= $size) {
$loc++;
}
}

print Dumper(\@groups);
print "---------------------------------\n";

my @arr;
foreach my $let (@words) {
push @arr, $let;
if (@arr >= $size) {
print "@{[ splice @arr, 0 ]}\n";
}
}
 
M

Mumia W.

Mirco said:
[...]
BTW.: But how would one translate
this to a foreach() loop without
nukeing the array;
[...]

Another way is to join the elements with a delimiter and use m// to
split them into groups:

use strict;
use warnings;
use Data::Dumper;

my $delimiter = ',';
my @data = (1, 2, 1000, 2000, 80, 84, 206, 370);
my @data2 =
map { [ m/(\d+)$delimiter*/g ] }
map { m/(?:[[:alnum:]]+$delimiter*){2}/g }
join $delimiter, @data;

foreach my $grp (@data2) {
print "@$grp\n";
}
 
M

Mirco Wahab

Thus spoke Mirco Wahab (on 2006-06-01 12:29):
Thus spoke Mirco Wahab

After working through your helpful examples
here, I came up finally with some kind of
'function' that spits out sub lists into
a foreach context.

Glad to hear some hints and tips for that
(and - of course - what went wrong ;-)

#!/usr/bin/perl
use strict;
use warnings;

# the brand new 'splyce_by' function:

sub splyce_by {
my @l; my $n = shift;
push @l, [@_[$_*$n..$_*$n+$n-1]] for 0..($#_/$n);
splice @{$l[$#l]}, @_%$n,$n-@_%$n, '' if @_ % $n;
return @l;
}

# this is how it is used:

my @arr = split //, 'thisisnomoreuglyanymore';
my $n = 5;

print "@$_,\n" for splyce_by $n, @arr;

# prints $n [sublists] but doesn't kill @arr
# t h i s i,
# s n o m o,
# ...

Thanks & regards

Mirco
 
P

Paul Lalli

Ferry said:
Mumia W.:


Why? As long as sort {} isn't used...

That advice should really be "Avoid using $a and $b except in a sort
subroutine". $a and $b are special. They are not subject to
strictures:

#!/usr/bin/perl
use strict;
use warnings;

sub foo {
print "A: $a, B: $b\n";
}

my ($a, $b) = (5, 10);

foo();
__END__
$ perl ab.pl
Name "main::a" used only once: possible typo at ab.pl line 6.
Name "main::b" used only once: possible typo at ab.pl line 6.
Use of uninitialized value in concatenation (.) or string at ab.pl line
6.
Use of uninitialized value in concatenation (.) or string at ab.pl line
6.
A: , B:
But wouldn't it be a nice idea to issue a warning
message in this case (with 'use warnings')?

As you can see, there are plenty of warnings for certain cases of
accidental $main::a and $main::b usage. What warning, exactly, are you
suggesting be added?

Paul Lalli
 
B

Ben Morrow

Quoth "Ferry Bolhar said:
Paul Lalli:
That advice should really be

"Avoid using $a and $b except in a sort subroutine".
[...]

What warning, exactly, are you suggesting be added?

Well, perhaps exactly what you've written above?

Or - because $a and $b can be seen as special variables
like $/:

"Can't use global $a in "my" at ...

They aren't, though. The situation is much more complicated and crufty
than that. Consider

~% perl -le'$a = "foo"; my $a = "bar"; print $a; print $main::a'
bar
foo

So $a can be C<my>ed, just like any other by-default-global name. Then
consider

~% perl -le'my $a = "bar"; print sort {warn $a} qw/a b/;'
bar at -e line 1
ba

So C<my>ing $a will break all sort subs in that scope. So don't do that
:). A possibility would be to warn if a sort sub is compiled against a
lexical $a/$b rather than the correct package vars: you could try suggesting
it to p5p.

Ben
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,263
Messages
2,571,064
Members
48,769
Latest member
Clifft

Latest Threads

Top