Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Slice an array of hashes?

Reply
Thread Tools

Slice an array of hashes?

 
 
Graham
Guest
Posts: n/a
 
      09-10-2003
Is it possible to slice a list of hashes?

I read in data into the @data array as follows:

while ( $i < $numLev )
{
$line = <$fh>; # Take
next line
$line =~ s/^\s+|\s+$//g; # Strip
whitespace
$line =~ s/,/ /g; #
Replace commas
@prf = ( @prf, (split /\s+/, $line) ); # Get the data
$i = $#prf + 1; # Update
total
}

@data = (@data, {"id"=>$id, "units"=>$units,
"data"=>[@prf]});
}

I want to find all the indices of atm where $id = "foo" or "bar" and
extract them into a new data array called data2.

Alas, at this point I cannot even slice into @data and select the "id"
fields.

print $atm[(0..2)]; # Gives: HASH(0x121064)
print @atm[(0..2)]; # Gives:
HASH(0x121064)HASH(0x11a0e0)HASH(0x112ce
print @atm[(0..2)]{"id"}; # Gives: compilation error.
print $atm[(0..2)]{"id"}; # Gives: string id tag for index 2

Thanks.
 
Reply With Quote
 
 
 
 
Matija Papec
Guest
Posts: n/a
 
      09-10-2003
X-Ftn-To: Graham

http://www.velocityreviews.com/forums/(E-Mail Removed) (Graham) wrote:
> while ( $i < $numLev )
> {
> $line = <$fh>; # Take
>next line
> $line =~ s/^\s+|\s+$//g; # Strip
>whitespace
> $line =~ s/,/ /g; #
>Replace commas
> @prf = ( @prf, (split /\s+/, $line) ); # Get the data


You'll be beter with
push @prf, ..
rather then
@prf = @prf, ..

> $i = $#prf + 1; # Update


$i = @prf is more classic way to do the same thing.

> @data = (@data, {"id"=>$id, "units"=>$units,
>"data"=>[@prf]});
>I want to find all the indices of atm where $id = "foo" or "bar" and
>extract them into a new data array called data2.


You don't have atm in above example but I'll /guess/ it looks like @data,

#untested
my @idx = grep $atm[$_]{id} =~ /^(?:foo|bar)$/, 0 .. $#atm;

>Alas, at this point I cannot even slice into @data and select the "id"
>fields.
>
> print $atm[(0..2)]; # Gives: HASH(0x121064)


This is same as $atm[0], as you're here refering to scalar, not array slice.
btw, you don't need braces around range.

> print @atm[(0..2)]; # Gives:
>HASH(0x121064)HASH(0x11a0e0)HASH(0x112ce
> print @atm[(0..2)]{"id"}; # Gives: compilation error.
> print $atm[(0..2)]{"id"}; # Gives: string id tag for index 2


perldoc perlref is your friend.
Try,
use Data:umper;
print Dumper @atm;



--
Matija
 
Reply With Quote
 
 
 
 
Chief Squawtendrawpet
Guest
Posts: n/a
 
      09-10-2003
Graham wrote:
> I want to find all the indices of atm where $id = "foo" or "bar" and
> extract them into a new data array called data2.


Your code uses @data, but your follow-up discussion speaks of @atm. I
assume they are the same.

Things like @atm[0..2]{id} don't make sense and give an error, as you
found out. Before you can get access to the items deeper in the data
structure (say, for the 'id' key), you have to commit to a subscript
at the higher levels; otherwise, Perl doesn't know which 'id' value to
grab.

Something like this would allow you to select items from @atm
according to the 'id' characteristics (code not tested):
@atm2 = grep { $_->{id} eq 'foo' } @atm;

Or if you want indexes to @atm instead of the hash refs themselves
(also not tested):
@ind = grep { $atm[$_]{id} eq 'foo' } 0 .. $#atm;

As a side note, use:
push @data, {HASH};
instead of code like this:
@data = (@data, {HASH});

Chief S.
 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      09-10-2003
Graham wrote:
>
> Is it possible to slice a list of hashes?


Yes.


> I read in data into the @data array as follows:
>
> while ( $i < $numLev )
> {
> $line = <$fh>; # Take next line
> $line =~ s/^\s+|\s+$//g; # Strip whitespace
> $line =~ s/,/ /g; # Replace commas
> @prf = ( @prf, (split /\s+/, $line) ); # Get the data
> $i = $#prf + 1; # Update total
> }


Better written as:

while ( my $line = <$fh> ) { # Take next line
s/^\s+//, s/\s+$// for $line; # Strip whitespace
$line =~ tr/,/ /; # Replace commas
push @prf, split ' ', $line; # Get the data
last if @prf >= $numLev; # Update total
}


> @data = (@data, {"id"=>$id, "units"=>$units, "data"=>[@prf]});


push @data, { id => $id, units => $units, data => [@prf] };


> }
>
> I want to find all the indices of atm where $id = "foo" or "bar" and
> extract them into a new data array called data2.
>
> Alas, at this point I cannot even slice into @data and select the "id"
> fields.
>
> print $atm[(0..2)]; # Gives: HASH(0x121064)
> print @atm[(0..2)]; # Gives:
> HASH(0x121064)HASH(0x11a0e0)HASH(0x112ce
> print @atm[(0..2)]{"id"}; # Gives: compilation error.
> print $atm[(0..2)]{"id"}; # Gives: string id tag for index 2


for my $hash ( @atm[ 0 .. 2 ] ) {

if ( $hash->{ id } eq 'foo' or $hash->{ id } eq 'bar' ) {

# do stuff with $hash->{ id }
# or $hash->{ units } or $hash->{ data }



John
--
use Perl;
program
fulfillment
 
Reply With Quote
 
Graham
Guest
Posts: n/a
 
      09-10-2003
news:<(E-Mail Removed). com>...
>> #untested
>> my @idx = grep $atm[$_]{id} =~ /^(?:foo|bar)$/, 0 .. $#atm;


Thanks a lot Matija! That is very close to what I want. The only
trouble is that 'foo' and 'bar' are given in a command line option and
I cannot seem to build a (for lack of a better word) 'dynamic' regex
that is composed of my command line options.

What is wrong with:

$search = "\^(\?:" . join("|", @search) . ")\$";
my @idx = grep $atm[$_]{"id"} =~ /$search/, 0 .. $#atm;

Thanks again!
 
Reply With Quote
 
Quantum Mechanic
Guest
Posts: n/a
 
      09-10-2003
(E-Mail Removed) (Graham) wrote in message news:<(E-Mail Removed). com>...
> Is it possible to slice a list of hashes?


Yes. But not as a literal slice, not the way you intended.

If you build @data like this:

@data = (@data, {"id"=>$id, "units"=>$units, "data"=>[@prf]});

then this will give you a slice:

@slice = @data[0,3,7..19];

But @slice now contains hashrefs, not just the "id" values you wanted.

To get the list of indices matching "foo" or "bar:

@indices = map { $data[$_]{id} =~ /^foo|bar$/ } 0..@data-1;

If instead you want the subset of @data itself:

@subset = map { $_->{id} =~ /^foo|bar$/ } @data;

But syntax like this:

@ids = @data[0..2]{"id"}

is equivlent to:

@ids = $data[2]{"id"}

which is the last index listed in the slice, regardless of the slice
indices or their order. [I tried this on ActivePerl 5.8.0.]

Someone more familiar with perlguts can provide an explanation, but it
appears that once the slice is generated, Perl treats it as a
comma-separated list, so only the last "expression" is returned.

-QM
 
Reply With Quote
 
Matija Papec
Guest
Posts: n/a
 
      09-11-2003
X-Ftn-To: Graham

(E-Mail Removed) (Graham) wrote:
>>> #untested
>>> my @idx = grep $atm[$_]{id} =~ /^(?:foo|bar)$/, 0 .. $#atm;

>
>Thanks a lot Matija! That is very close to what I want. The only
>trouble is that 'foo' and 'bar' are given in a command line option and
>I cannot seem to build a (for lack of a better word) 'dynamic' regex
>that is composed of my command line options.
>
>What is wrong with:
>
> $search = "\^(\?:" . join("|", @search) . ")\$";
> my @idx = grep $atm[$_]{"id"} =~ /$search/, 0 .. $#atm;


There is nothing wrong with your $search, you could eventually remove first
two unneeded backslashes and compile regex for faster execution,
$search = qr/$search/;

...and make sure that @search and @atm contain things that you want there.


--
Matija
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Array slice to end of array of indeterminate size niall.macpherson@ntlworld.com Perl Misc 9 05-22-2006 06:34 PM
type safe array slice Antony Sequeira Java 6 03-28-2006 10:09 AM
array slice question kr Perl 3 08-13-2004 07:39 PM
How to slice range of array along a (a-priori unknown) axis? Maarten van Reeuwijk Python 3 02-05-2004 10:58 AM
slice of multidimensional array Dave Bazell Perl 2 07-24-2003 11:17 PM



Advertisments