tags:

views:

130

answers:

4

Hi,

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.

+6  A: 

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.

David Dorward
Hi, Mvan and DavidThanks for the reply. The problem is the same thing what u told. I want to create a data structure with the array contents. Condition is that array contents will have data start with 'name'. Is there any way to overcome this apart from having data that does not have 'name' ?? help me pls ..
Senthil kumar
You have a data structure (the array). If you want a different data structure, then you need to design that data structure and then put the data into it. A hash key maps onto one, and only one, value. So if the design of your data structure involves multiple keys with the same name, then a simple hash won't do the job. I suggested one alternative in my answer. Another would be an array of hashrefs or arrayrefs.
David Dorward
+2  A: 

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.

FM
Buddy thanks for ur answer and reply ...
Senthil kumar
+6  A: 

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'
                    ]
        };
Greg Bacon
Great answer man... u spent some good time for me.. i will go with your approach
Senthil kumar
+1  A: 

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();  
vol7ron
Buddy thanks for ur answer and reply ...
Senthil kumar
no problem. don't forget to upvote those answers you found useful and if your question was answered, hit the checkmark on the answer that solved your problem (or the one you found most useful) - when you ask a question there's an accept rate, right now yours is at 0%, which means you never select answers. people with low accept rates are less likely to get replies.
vol7ron
your accept rate already went up 20% :) congrats
vol7ron