Ask a Question related to PERL Miscellaneous, Design and Development.
-
Graham #1
Slice an array of hashes?
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(0x112ce8)
print @atm[(0..2)]{"id"}; # Gives: compilation error.
print $atm[(0..2)]{"id"}; # Gives: string id tag for index 2
Thanks.
Graham Guest
-
Printing Array of Hashes
Hi John, I received your code. Thanks. I would like to know how to check the values of the keys in the hash. I checked the Perl cookbook and... -
Array#slice oddity...
It appears that if you use slice or slice! with a length argument, it returns an array even if the index is out of range: irb(main):001:0> a = ... -
Sorting an array of hashes by 2 values
Hello, I have an array of variable size which contains a hash with three keys: count, name, description. I have a call to sort which sorts this... -
adding to an array of hashes
When I run the following: for($k=0;$k<3;$k++){ $r->{'NUM'} = $k; #$temp->{'NUM'} = $k; #$r = $temp; print "added: $r->{'NUM'}\n"; } ... -
Comparing 2 hashes of array refs
On 11 Jul 2003, simo wrote: It's best to cut and paste from your code, as opposed to retyping. Hashes are defined by parenthesis, not by... -
Matija Papec #2
Re: Slice an array of hashes?
X-Ftn-To: Graham
[email]GrahamWilsonCA@yahoo.ca[/email] (Graham) wrote:You'll be beter with> 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
push @prf, ..
rather then
@prf = @prf, ..
$i = @prf is more classic way to do the same thing.> $i = $#prf + 1; # Update
You don't have atm in above example but I'll /guess/ it looks like @data,> @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.
#untested
my @idx = grep $atm[$_]{id} =~ /^(?:foo|bar)$/, 0 .. $#atm;
This is same as $atm[0], as you're here refering to scalar, not array slice.>Alas, at this point I cannot even slice into @data and select the "id"
>fields.
>
> print $atm[(0..2)]; # Gives: HASH(0x121064)
btw, you don't need braces around range.
perldoc perlref is your friend.> print @atm[(0..2)]; # Gives:
>HASH(0x121064)HASH(0x11a0e0)HASH(0x112ce8)
> print @atm[(0..2)]{"id"}; # Gives: compilation error.
> print $atm[(0..2)]{"id"}; # Gives: string id tag for index 2
Try,
use Data::Dumper;
print Dumper @atm;
--
Matija
Matija Papec Guest
-
Chief Squawtendrawpet #3
Re: Slice an array of hashes?
Graham wrote:
Your code uses @data, but your follow-up discussion speaks of @atm. I> I want to find all the indices of atm where $id = "foo" or "bar" and
> extract them into a new data array called data2.
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.
Chief Squawtendrawpet Guest
-
John W. Krahn #4
Re: Slice an array of hashes?
Graham wrote:
Yes.>
> Is it possible to slice a list of hashes?
Better written as:> 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
> }
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
}
push @data, { id => $id, units => $units, data => [@prf] };> @data = (@data, {"id"=>$id, "units"=>$units, "data"=>[@prf]});
for my $hash ( @atm[ 0 .. 2 ] ) {> }
>
> 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(0x112ce8)
> print @atm[(0..2)]{"id"}; # Gives: compilation error.
> print $atm[(0..2)]{"id"}; # Gives: string id tag for index 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
John W. Krahn Guest
-
Graham #5
Re: Slice an array of hashes?
news:<eda30d78.0309100645.64745eb2@posting.google. com>...
Thanks a lot Matija! That is very close to what I want. The only>> #untested
>> my @idx = grep $atm[$_]{id} =~ /^(?:foo|bar)$/, 0 .. $#atm;
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!
Graham Guest
-
Quantum Mechanic #6
Re: Slice an array of hashes?
[email]GrahamWilsonCA@yahoo.ca[/email] (Graham) wrote in message news:<eda30d78.0309100645.64745eb2@posting.google. com>...
Yes. But not as a literal slice, not the way you intended.> Is it possible to slice a list of hashes?
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
Quantum Mechanic Guest
-
Matija Papec #7
Re: Slice an array of hashes?
X-Ftn-To: Graham
[email]GrahamWilsonCA@yahoo.ca[/email] (Graham) wrote:There is nothing wrong with your $search, you could eventually remove first>>>> #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;
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
Matija Papec Guest



Reply With Quote

