Senthil kumar
Senthil kumar

Reputation: 993

Perl Hashes and array

I have an array with 28 elements.

I copied array contents into a hash.

If i try to print the hash it is not showing all keys and values.

Code is given below,

@new;
%hash = @new;
foreach $food (keys %hash) 
{
 $color = $hash{$food};
 print "$food is $color.\n";
}

Output is ::

attribute is Mandatory.
min is 0X00.
value is 778.
max is 9940486857.
name is Security_header.
type is nibble.

The array @new contents are,

name Protocol_discriminator attribute Mandatory value 778 min 0X00 max 994048685 value 7 min 0 max F name Security_header attribute Mandatory type nibble value 778 min 0X00 max 9940486857

I want all the contents of the array to be copied in the hash and to be printed, if i try to traverse the hash. but some how only part of the array content is copied into the hash.

Can anyone help to overcome this problem. I am struggling for the past two days.

Thanks Senthil.

Upvotes: 2

Views: 522

Answers (4)

vol7ron
vol7ron

Reputation: 42095

Simple Answer: A hash should be thought of as an associative array.
There is one unique key and each key has a value (can be a hash).

Your Problem: Every time you encounter a key that already exists, you are replacing the value.


Solution:

#!/usr/bin/perl -w    

use strict;   

   sub main{ 
      $" = ", ";                                         # format array output

      my %hash;   
      my @arr   =  ( ['color' ,'red' ]
                   , ['color' ,'blue']
                   , ['size'  ,'1'   ]
                   , ['size'  ,'2'   ] 
                   );

      foreach my $rcd (@arr) {
         push @{$hash{$$rcd[0]}} , $$rcd[1];
      }          

      print "@{$hash{color}} \n";                        # prints: red, blue
   }    

   main();  

Upvotes: 1

Greg Bacon
Greg Bacon

Reputation: 139411

Let's change the presentation of @new to show what's going on:

my @new = qw/
  attribute Mandatory
  attribute Mandatory
  max       994048685
  max       9940486857
  max       F
  min       0
  min       0X00
  min       0X00
  name      Protocol_discriminator
  name      Security_header
  type      nibble
  value     7
  value     778
  value     778
/;

Perl hash keys are unique, so when assigning @new to %hash, the last value for a given key “wins.” For a simple example

$ perl -le '%h = qw/1 a 1 b 1 c/; print $h{1}'
c

Given that you have many values for the same key, use a data structure that can handle it:

my %hash;
for (my $i = 0; $i < @new; $i += 2) {
  my($name,$val) = @new[$i,$i+1];
  push @{ $hash{$name} } => $val;
}

If you don't mind destroying @new, the code can be a little more idiomatic:

while (@new) {
  my($name,$val) = splice @new, 0, 2;
  push @{ $hash{$name} } => $val;
}

This means every value associated with a given key in %hash is a reference to an array of values. The push operator expects an array and not a reference, so we use @{ ... } to dereference it.

If you aren't familiar with Perl references, be sure to read the perlref and perllol documentation.

One way to print the values in %hash is

foreach my $name (sort keys %hash) {
  print "$name = [@{ $hash{$name} }]\n";
}

Output:

attribute = [Mandatory Mandatory]
max = [994048685 9940486857 F]
min = [0 0X00 0X00]
name = [Protocol_discriminator Security_header]
type = [nibble]
value = [7 778 778]

Another handy trick for printing and debugging complex data structures is the Data::Dumper module:

use Data::Dumper;
print Dumper \%hash;

which prints

$VAR1 = {
          'attribute' => [
                           'Mandatory',
                           'Mandatory'
                         ],
          'value' => [
                       '7',
                       '778',
                       '778'
                     ],
          'min' => [
                     '0',
                     '0X00',
                     '0X00'
                   ],
          'name' => [
                      'Protocol_discriminator',
                      'Security_header'
                    ],
          'max' => [
                     '994048685',
                     '9940486857',
                     'F'
                   ],
          'type' => [
                      'nibble'
                    ]
        };

Upvotes: 6

FMc
FMc

Reputation: 42411

The information in the @new array suggests that you need a richer data structure. I don't know the details of your problem, but here's the structure that I see.

my @data = (
    # Each data item is a hash reference, with four
    # possible keys: name, attribute, type, and vals.
    # I added the 'vals' key to handle the other information.
    {
        name      => 'Protocol_discriminator',
        attribute => 'Mandatory',
        type      => undef,
        # The 'vals' key points to an array reference.
        # That array contains a list of hash references.
        vals => [
            { value => 778, min => '0X00', max => 994048685 },
            { value =>   7, min =>      0, max =>       'F' },
        ],
    },

    # Another data item.
    {
        name      => 'Security_header',
        attribute => 'Mandatory',
        type      => 'nibble',
        vals => [
            { value => 778, min => '0X00', max => 9940486857 },
        ],
    },
);

To learn how to work with complex data structures, see perlreftut, perldsc, and perllol.

Also, your scripts should always contain use strict and use warnings.

Upvotes: 2

Quentin
Quentin

Reputation: 943100

You have multiple keys with the same name, so you are overwriting the data.

You need to rethink your approach.

Possibly you need a smarter algorithm to construct your hash (e.g. putting values in an array ref instead of just as a simple value). Possibly you need to forget about the hash and just loop over the array with a for loop that increments by 2 each time round.

Upvotes: 6

Related Questions