Slice an array of hashes?

Ask a Question related to PERL Miscellaneous, Design and Development.

  1. #1

    Default 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

  2. Similar Questions and Discussions

    1. 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...
    2. 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 = ...
    3. 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...
    4. 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"; } ...
    5. 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...
  3. #2

    Default Re: Slice an array of hashes?

    X-Ftn-To: Graham

    [email]GrahamWilsonCA@yahoo.ca[/email] (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(0x112ce8)
    > 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::Dumper;
    print Dumper @atm;



    --
    Matija
    Matija Papec Guest

  4. #3

    Default Re: Slice an array of hashes?

    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.
    Chief Squawtendrawpet Guest

  5. #4

    Default Re: Slice an array of hashes?

    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(0x112ce8)
    > 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
    John W. Krahn Guest

  6. #5

    Default Re: Slice an array of hashes?

    news:<eda30d78.0309100645.64745eb2@posting.google. 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!
    Graham Guest

  7. #6

    Default Re: Slice an array of hashes?

    [email]GrahamWilsonCA@yahoo.ca[/email] (Graham) wrote in message news:<eda30d78.0309100645.64745eb2@posting.google. 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
    Quantum Mechanic Guest

  8. #7

    Default Re: Slice an array of hashes?

    X-Ftn-To: Graham

    [email]GrahamWilsonCA@yahoo.ca[/email] (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
    Matija Papec Guest

Posting Permissions

  • You may not post new threads
  • You may post replies
  • You may not post attachments
  • You may not edit your posts

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139