while each hash, why not array

R

Robert Wallace

I can extract two values at a time from a hash with while, why not with
an array?

that is with
%hashish = ( a => 1, b => 2, c => 3);
I can:
while (($k,$v) = each %hashish ){
print "$k => $v\n";
}


why not:
while (($k,$v) = each @arr){
print "$k => $v\n";
}
 
A

A. Sinan Unur

I can extract two values at a time from a hash with while, why not with
an array?

You are extracting one key and one value from the hash.
that is with
%hashish = ( a => 1, b => 2, c => 3);
I can:
while (($k,$v) = each %hashish ){
print "$k => $v\n";
}


why not:
while (($k,$v) = each @arr){
print "$k => $v\n";
}

Because in an array, values are indexed by integers, not by arbitrary
keys.

for(my $i = 0; $i != @arr; ++$i) {
print "$i => $arr[$i]\n";
}

Sinan.
 
D

Darren Dunham

Robert Wallace said:
I can extract two values at a time from a hash with while, why not with
an array?
that is with
%hashish = ( a => 1, b => 2, c => 3);
I can:
while (($k,$v) = each %hashish ){
print "$k => $v\n";
}

why not:
while (($k,$v) = each @arr){
print "$k => $v\n";
}

Hashes keep the overhead of a counter to note where each should look.
Arrays do not. If you only need to read through the array once, you
could just splice them off the front.

while (($k, $v) = splice(@arr, 0, 2))
{ ... }

You could shove the data onto another array to keep track of it, but if
you're going to need the data twice, I'd rather do an index loop
instead.

for ($i = 0; $i < @arr ; $i += 2)
{ ($k, $v) = @arr[$i,$i+1];
...
}
 
M

Michael P. Broida

Robert said:
I can extract two values at a time from a hash with while, why not with
an array?

that is with
%hashish = ( a => 1, b => 2, c => 3);
I can:
while (($k,$v) = each %hashish ){
print "$k => $v\n";
}

This is giving you (I think) the key and the value
for ONE hash entry, NOT two keys or two values.
why not:
while (($k,$v) = each @arr){
print "$k => $v\n";
}

Arrays don't have "keys", so what would you expect
$k and $v to contain?? If you want an index and a
value (as the print statement seems to indicate,
use:

while ($v = each @arr){
print "$k => $v\n";
$k++;
}

Mike
 
M

Malcolm Dew-Jones

Robert Wallace ([email protected]) wrote:
: I can extract two values at a time from a hash with while, why not with
: an array?


: that is with
: %hashish = ( a => 1, b => 2, c => 3);
: I can:
: while (($k,$v) = each %hashish ){
: print "$k => $v\n";
: }


: why not:
: while (($k,$v) = each @arr){
: print "$k => $v\n";
: }

Because you aren't extracting two "values" at a time from the hash (and
you're not extracting them using "while" either, though that's just
pedantics).

`each' extracts one key and the associated value from a hash.

each is designed to work on hashes, not arrays.

If each worked on array's (which would look nice sometimes) then it would
presumably extract the next, single, value, which is basically what
foreach does already.

# hypothetical "each" of array

while ( $v = each @arr)

# what you can do today

foreach my $v (@arr)
 
K

Keith Keller

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

%hashish = ( a => 1, b => 2, c => 3);
while (($k,$v) = each %hashish ){
print "$k => $v\n";
}


# why not:
while (($k,$v) = each @arr){
print "$k => $v\n";
}

What values do you want assigned to $k and $v in each iteration? I can
think of two different methods, both of which might make sense depending
on context.

1) $k=$arr[0],$v=$arr[1] on first iteration, then $k=$arr[2],$v=$arr[3],
and so on

2) $k=0,$v=$arr[0], then $k=1,$v=$arr[1], and so on

The second is easily accomplished with a rewrite of the loop (I think
others in the thread have already addressed it). If you mean the first,
I believe this might work:

%hash2=@arr; # if @arr has an even number of elements

If you mean something else you'll need to elaborate: what, exactly, would
each @arr do?

- --keith

- --
(e-mail address removed)-francisco.ca.us
(try just my userid to email me)
AOLSFAQ=http://wombat.san-francisco.ca.us/cgi-bin/fom

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iEYEARECAAYFAj+W7o0ACgkQhVcNCxZ5ID+1IACfZCHuK60wIgUbejhMbE7g2gp2
ANUAnRifh1wwQLCnCf5/vslf+dfuuoxF
=rEMD
-----END PGP SIGNATURE-----
 
M

Michael P. Broida

Michael P. Broida said:
while ($v = each @arr){
print "$k => $v\n";
$k++;
}

Well, my syntax was wrong ("each" with an array),
but the thought was good. <grin> Change that to:

$k = 0;
foreach $v (@arr){
print "$k => $v\n";
$k++;
}

Mike
 
A

Anno Siegel

Abigail said:
Malcolm Dew-Jones ([email protected]) wrote on MMMDCCIV September
MCMXCIII in <URL:{} Robert Wallace ([email protected]) wrote:
{} : I can extract two values at a time from a hash with while, why not with
{} : an array?
{}
{}
{} : that is with
{} : %hashish = ( a => 1, b => 2, c => 3);
{} : I can:
{} : while (($k,$v) = each %hashish ){
{} : print "$k => $v\n";
{} : }
{}
{}
{} : why not:
{} : while (($k,$v) = each @arr){
{} : print "$k => $v\n";
{} : }
{}
{} Because you aren't extracting two "values" at a time from the hash (and
{} you're not extracting them using "while" either, though that's just
{} pedantics).
{}
{} `each' extracts one key and the associated value from a hash.
{}
{} each is designed to work on hashes, not arrays.
{}
{} If each worked on array's (which would look nice sometimes) then it would
{} presumably extract the next, single, value, which is basically what
{} foreach does already.
{}
{} # hypothetical "each" of array
{}
{} while ( $v = each @arr)
{}
{} # what you can do today
{}
{} foreach my $v (@arr)


Nah, a hypothetical 'each' for arrays would be:

while (my ($key, $value) = each @array) {
# $key is the index, $value the value.
}

That would be my idea too of what "each" should mean for an array.
However, there are other interpretations. Besides Malcolm's (essentially
equivalent to "foreach"), there was

while (my ($key, $value) = each @array) {
# $key is an even-indexed element, $value an odd-indexed element
}

which is also a plausible generalization of the behavior of "each",
though, I believe, not a very useful one.

Maybe this ambiguity is another reason why "each" hasn't been generalized.

Anno
 
G

Greg Bacon

: Nah, a hypothetical 'each' for arrays would be:
:
: while (my ($key, $value) = each @array) {
: # $key is the index, $value the value.
: }

Sweet! Something like this?

$ cat ArrayEach.pm
package ArrayEach;

use strict;

require Exporter;
our @ISA = 'Exporter';
our @EXPORT = 'each';

# next index
my %iter;

sub each (\[%@]) {
my $that = shift;

if (ref($that) eq "HASH") {
return CORE::each %$that;
}

if (defined $iter{$that} && $iter{$that} >= @$that) {
delete $iter{$that};
return;
}

my $k = $iter{$that}++ || 0;
my $v = $that->[$k];

wantarray ? ($k, $v) : $v;
}

1;

$ cat test-each
#! /usr/local/bin/perl

use warnings;
use strict;

use ArrayEach;

my %h = (a => 1, b => 2, c => 3);
my @a = qw/ apples oranges bananas /;

my %core;
while (my($k,$v) = CORE::each %h) {
$core{$k} = $v;
}

my %new;
while (my($k,$v) = each %h) {
$new{$k} = $v;
}

for (keys %core) {
warn "'$_' missing from new\n"
unless exists $new{$_} && $new{$_} eq $core{$_};
}

for (keys %new) {
warn "'$_' extra in new\n"
unless exists $core{$_};
}

my @new;
while (my($k,$v) = each @a) {
push @new, [$k,$v];
}

warn "too many results: ", scalar @new, "\n"
unless @new == @a;

for (my $i = 0; $i < @new; ++$i) {
warn "bad key at $i ($new[$i]->[0])\n"
unless $i == $new[$i]->[0];

warn "bad value at $i ($new[$i]->[1])\n"
unless $a[$i] eq $new[$i]->[1];
}

print "Done\n";

__END__

Greg
 
A

Anno Siegel

Abigail said:
Anno Siegel ([email protected]) wrote on MMMDCCV September
MCMXCIII in <URL:() >
() >
() > Nah, a hypothetical 'each' for arrays would be:
() >
() > while (my ($key, $value) = each @array) {
() > # $key is the index, $value the value.
() > }
()
() That would be my idea too of what "each" should mean for an array.
() However, there are other interpretations. Besides Malcolm's (essentially
() equivalent to "foreach"), there was
()
() while (my ($key, $value) = each @array) {
() # $key is an even-indexed element, $value an odd-indexed element
() }
()
() which is also a plausible generalization of the behavior of "each",
() though, I believe, not a very useful one.
()
() Maybe this ambiguity is another reason why "each" hasn't been generalized.


My guess the reason 'each' hasn't been generalized is that arrays don't
have slots to keep the state of the iterator. Hashes have them. Adding
them to arrays means adding an extra integer to all AVs. Considering that
'each @array' will be used far less than 'each %hash', the price is not
worth paying.

Having the iterator incorporated in the hash itself isn't ideal -- it's
the reason why we can't nest "each"- and "keys"-loops over the same hash.
One could also take the opportunity and implement both iterators differently.

Not bloody likely, I know. I wonder how Perl 6 will behave in that respect.

Anno
 
A

Anno Siegel

Abigail said:
Greg Bacon ([email protected]) wrote on MMMDCCV September MCMXCIII in
``
`` : Nah, a hypothetical 'each' for arrays would be:
`` :
`` : while (my ($key, $value) = each @array) {
`` : # $key is the index, $value the value.
`` : }
``
`` Sweet! Something like this?

I thought of that myself, but it doesn't work. The problem is that
memory addresses aren't unique over time; they are reused:

One could bless arrays when they are iterated over and take care of
the %iter entry in DESTROY.

Besides being absurd, it is fragile. Scratch that :)

Anno
 
U

Uri Guttman

AS> That would be my idea too of what "each" should mean for an array.
AS> However, there are other interpretations. Besides Malcolm's (essentially
AS> equivalent to "foreach"), there was

AS> while (my ($key, $value) = each @array) {
AS> # $key is an even-indexed element, $value an odd-indexed element
AS> }

AS> which is also a plausible generalization of the behavior of "each",
AS> though, I believe, not a very useful one.

perl6 has that in the form of the un/zip function (it merges/splits
lists).

and it is useful when you have a set of pairs (maybe config stuff) that
needs to be processed in order. getting the next N elements into a list
of scalars (perl6 can do wierd combos of this as well) is a highly
desired function.

AS> Maybe this ambiguity is another reason why "each" hasn't been generalized.

well delete was changed to support (the soon to be dead)
pseudo-hashes. each could have been generalized to return the
index/value pair which is not a bad idea but i doubt i ever would need
it. it would be exteremely rare to find index driven code in any of my
source.

uri
 
M

Malcolm Dew-Jones

Anno Siegel ([email protected]) wrote:
: > Anno Siegel ([email protected]) wrote on MMMDCCV September
: > MCMXCIII in <URL:: > () >
: > () >
: > () > Nah, a hypothetical 'each' for arrays would be:
: > () >
: > () > while (my ($key, $value) = each @array) {
: > () > # $key is the index, $value the value.
: > () > }
: > ()
: > () That would be my idea too of what "each" should mean for an array.
: > () However, there are other interpretations. Besides Malcolm's (essentially
: > () equivalent to "foreach"), there was
: > ()
: > () while (my ($key, $value) = each @array) {
: > () # $key is an even-indexed element, $value an odd-indexed element
: > () }
: > ()
: > () which is also a plausible generalization of the behavior of "each",
: > () though, I believe, not a very useful one.
: > ()
: > () Maybe this ambiguity is another reason why "each" hasn't been generalized.
: >
: >
: > My guess the reason 'each' hasn't been generalized is that arrays don't
: > have slots to keep the state of the iterator. Hashes have them. Adding
: > them to arrays means adding an extra integer to all AVs. Considering that
: > 'each @array' will be used far less than 'each %hash', the price is not
: > worth paying.

: Having the iterator incorporated in the hash itself isn't ideal -- it's
: the reason why we can't nest "each"- and "keys"-loops over the same hash.
: One could also take the opportunity and implement both iterators differently.

: Not bloody likely, I know. I wonder how Perl 6 will behave in that respect.

perl 6, no idea, but the way other languages handle it would be to create
an iteration object, so you could imagine

my $iter1 = iterator_for %hash;

while ( my ($k,$v) = $iter->next ) or such like

OR
store a context handle or other identifier as an optional argument to the
each

while ( my ($k,$v) = each(%hash,$iter1) )
 
G

Greg Bacon

: [...]
: Not bloody likely, I know. I wonder how Perl 6 will behave in that
: respect.

Thus sayeth Exegesis 6:

. . . Instead, we have to consider both the index and the value of
each data element.

To do that we use the @data array's .kv method. Just as calling
the .kv method on a hash returns key, value, key, value, key,
value, etc., so too calling the .kv method on an array returns
index, value, index, value, index, value, etc. Then we just use a
parameterized block as our for block, specifying that it has two
arguments. That causes the for to grab two elements of the list
its iterating (i.e. one index and one value) on each iteration.

Then we simply test to see if the current index is any of those
specified in $is_sheep's array and, if so, we push the
corresponding value:

for @data.kv -> $index, $value {
if $index == any(@$is_sheep) { push %herd{$sheep}, $value }
else { push %herd{$goats}, $value }
}

See http://www.perl.com/pub/a/2003/07/29/exegesis6.html?page=8

Greg
 

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
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top