Loading ...
Sorry, an error occurred while loading the content.
 

Transforming a list into a hash of arrays

Expand Messages
  • jslay77
    I hope this is the appropriate forum to ask this question. assume I have a list like this: @input = ( 1 , hostname1 , 1 , hostname2 , 1 , hostname3 , 2 ,
    Message 1 of 5 , Feb 7, 2007
      I hope this is the appropriate forum to ask this question.

      assume I have a list like this:

      @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
      'hostname10', '2', 'hostname11', '3', 'hostname12');

      I want to turn this list into a hash of anonymous arrays...something
      like this I guess.

      %hash = (
      '1' => ['hostname1', 'hostname2', 'hostname3'],
      '2' => ['hostname10', 'hostname11'],
      '3' => ['hostname12'],
      );


      :)

      I hope I explained that appropriately.
      regards,
      J
    • Rob Biedenharn
      ... Why don t you post some code showing your attempt and then we can help you if it doesn t do what you expect? Here s a hint, to initialize a hash element
      Message 2 of 5 , Feb 7, 2007
        On Feb 7, 2007, at 10:58 AM, jslay77 wrote:

        > I hope this is the appropriate forum to ask this question.
        >
        > assume I have a list like this:
        >
        > @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
        > 'hostname10', '2', 'hostname11', '3', 'hostname12');
        >
        > I want to turn this list into a hash of anonymous arrays...something
        > like this I guess.
        >
        > %hash = (
        > '1' => ['hostname1', 'hostname2', 'hostname3'],
        > '2' => ['hostname10', 'hostname11'],
        > '3' => ['hostname12'],
        > );
        >
        >
        > :)
        >
        > I hope I explained that appropriately.
        > regards,
        > J

        Why don't you post some code showing your attempt and then we can
        help you if it doesn't do what you expect? Here's a hint, to
        initialize a hash element with an empty array if it doesn't already
        have a value, you can do this:

        $hash{$key} ||= [];

        I made a subroutine "array_to_hash" taking a list of values and
        returning a hash. My little script also used
        List::MoreUtils::natatime to get the pairs from the array, but that's
        not the only way. I also used Data::Dumper to produce the output to
        visually check the result like this:


        @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
        'hostname10', '2', 'hostname11', '3', 'hostname12');

        my %hash = array_to_hash @input;

        print Data::Dumper->Dump([\@input, \%hash], [qw(*input *hash)]);

        @input = (
        '1',
        'hostname1',
        '1',
        'hostname2',
        '1',
        'hostname3',
        '2',
        'hostname10',
        '2',
        'hostname11',
        '3',
        'hostname12'
        );
        %hash = (
        '1' => [
        'hostname1',
        'hostname2',
        'hostname3'
        ],
        '3' => [
        'hostname12'
        ],
        '2' => [
        'hostname10',
        'hostname11'
        ]
        );

        -Rob

        Rob Biedenharn http://agileconsultingllc.com
        Rob@...
      • jslay77
        ... Rob, Thanks for the quick response...and your $hash{$key} ||=[] hint :) I actually got around this whole thing by retrieving my data differently from
        Message 3 of 5 , Feb 7, 2007
          --- In perl-beginner@yahoogroups.com, Rob Biedenharn <Rob@...> wrote:
          >
          >
          > On Feb 7, 2007, at 10:58 AM, jslay77 wrote:
          >
          > > I hope this is the appropriate forum to ask this question.
          > >
          > > assume I have a list like this:
          > >
          > > @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
          > > 'hostname10', '2', 'hostname11', '3', 'hostname12');
          > >
          > > I want to turn this list into a hash of anonymous arrays...something
          > > like this I guess.
          > >
          > > %hash = (
          > > '1' => ['hostname1', 'hostname2', 'hostname3'],
          > > '2' => ['hostname10', 'hostname11'],
          > > '3' => ['hostname12'],
          > > );
          > >
          > >
          > > :)
          > >
          > > I hope I explained that appropriately.
          > > regards,
          > > J
          >
          > Why don't you post some code showing your attempt and then we can
          > help you if it doesn't do what you expect? Here's a hint, to
          > initialize a hash element with an empty array if it doesn't already
          > have a value, you can do this:
          >
          > $hash{$key} ||= [];
          >
          > I made a subroutine "array_to_hash" taking a list of values and
          > returning a hash. My little script also used
          > List::MoreUtils::natatime to get the pairs from the array, but that's
          > not the only way. I also used Data::Dumper to produce the output to
          > visually check the result like this:
          >
          >
          > @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
          > 'hostname10', '2', 'hostname11', '3', 'hostname12');
          >
          > my %hash = array_to_hash @input;
          >
          > print Data::Dumper->Dump([\@input, \%hash], [qw(*input *hash)]);
          >
          > @input = (
          > '1',
          > 'hostname1',
          > '1',
          > 'hostname2',
          > '1',
          > 'hostname3',
          > '2',
          > 'hostname10',
          > '2',
          > 'hostname11',
          > '3',
          > 'hostname12'
          > );
          > %hash = (
          > '1' => [
          > 'hostname1',
          > 'hostname2',
          > 'hostname3'
          > ],
          > '3' => [
          > 'hostname12'
          > ],
          > '2' => [
          > 'hostname10',
          > 'hostname11'
          > ]
          > );
          >
          > -Rob
          >
          > Rob Biedenharn http://agileconsultingllc.com
          > Rob@...
          >

          Rob,

          Thanks for the quick response...and your $hash{$key} ||=[] hint :)

          I actually got around this whole thing by retrieving my data differently from DBD::Oracle,
          however I was still intrigued at the problem...I believe I figured it out with your help.

          This does what I was looking for, however would there be a better way?

          @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2', 'hostname10', '2',
          'hostname11', '3', 'hostname12');
          my %hash;

          my %seen;
          my $key;
          for (@input; $i <= $#input; $i += 2) {
          if (! $seen{$input[$i]}++ ) {
          $hash{$input[$i]} ||= ["$input[$i + 1]"];
          } else {
          push @{$hash{$input[$i]}}, $input[$i + 1];
          next;
          }
          }


          foreach (sort keys %hash) {
          print "$_ --> @{$hash{$_}}\n";
          }
        • Rob Biedenharn
          ... You don t need this... ... You haven t used this... But you don t initialize $i (which tells me that you aren t using the -w option) ... Should be
          Message 4 of 5 , Feb 7, 2007
            On Feb 7, 2007, at 7:36 PM, jslay77 wrote:
            > --- In perl-beginner@yahoogroups.com, Rob Biedenharn <Rob@...> wrote:
            >> On Feb 7, 2007, at 10:58 AM, jslay77 wrote:
            >>> I hope this is the appropriate forum to ask this question.
            >>>
            >>> assume I have a list like this:
            >>>
            >>> @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
            >>> 'hostname10', '2', 'hostname11', '3', 'hostname12');
            >>>
            >>> I want to turn this list into a hash of anonymous arrays...something
            >>> like this I guess.
            >>>
            >>> %hash = (
            >>> '1' => ['hostname1', 'hostname2', 'hostname3'],
            >>> '2' => ['hostname10', 'hostname11'],
            >>> '3' => ['hostname12'],
            >>> );
            >>>
            >>>
            >>> :)
            >>>
            >>> I hope I explained that appropriately.
            >>> regards,
            >>> J
            >>
            >> Why don't you post some code showing your attempt and then we can
            >> help you if it doesn't do what you expect? Here's a hint, to
            >> initialize a hash element with an empty array if it doesn't already
            >> have a value, you can do this:
            >>
            >> $hash{$key} ||= [];
            >>
            >> I made a subroutine "array_to_hash" taking a list of values and
            >> returning a hash. My little script also used
            >> List::MoreUtils::natatime to get the pairs from the array, but that's
            >> not the only way. I also used Data::Dumper to produce the output to
            >> visually check the result like this:
            >>
            >>
            >> @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
            >> 'hostname10', '2', 'hostname11', '3', 'hostname12');
            >>
            >> my %hash = array_to_hash @input;
            >>
            >> print Data::Dumper->Dump([\@input, \%hash], [qw(*input *hash)]);
            >>
            >>
            >> -Rob
            >>
            >> Rob Biedenharn http://agileconsultingllc.com
            >> Rob@...
            >>
            >
            > Rob,
            >
            > Thanks for the quick response...and your $hash{$key} ||=[] hint :)
            >
            > I actually got around this whole thing by retrieving my data
            > differently from DBD::Oracle,
            > however I was still intrigued at the problem...I believe I figured
            > it out with your help.
            >
            > This does what I was looking for, however would there be a better way?
            >
            > @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3',
            > '2', 'hostname10', '2',
            > 'hostname11', '3', 'hostname12');
            > my %hash;
            >
            > my %seen;
            You don't need this...

            > my $key;
            You haven't used this...

            But you don't initialize $i (which tells me that you aren't using the
            -w option)

            > for (@input; $i <= $#input; $i += 2) {
            Should be < not <=, but you get lucky since you're incrementing by 2
            > if (! $seen{$input[$i]}++ ) {
            > $hash{$input[$i]} ||= ["$input[$i + 1]"];
            Unless you mean to stringify the values, you don't need the quotes
            just like you don't need them in the push.
            > } else {
            > push @{$hash{$input[$i]}}, $input[$i + 1];
            > next;
            > }
            > }

            Simplifying and you get (after really using the hint ;-)
            for (my $i = 0; $i < $#input; $i += 2) {
            push @{$hash{$input[$i]} ||= []}, $input[$i + 1];
            }

            > foreach (sort keys %hash) {
            > print "$_ --> @{$hash{$_}}\n";
            > }

            And for completeness now that you've done your version. Here's mine:

            #!/usr/bin/env perl -w
            use List::MoreUtils qw(natatime);
            use Data::Dumper;

            sub array_to_hash {
            my @args = @_;
            my %hash;

            my $iter = natatime 2, @args;
            while (my ($key, $val) = $iter->()) {
            $hash{$key} ||= [];
            push @{$hash{$key}}, $val;
            }
            return %hash;
            }

            @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
            'hostname10', '2', 'hostname11', '3', 'hostname12');
            my %hash = array_to_hash @input;

            print Data::Dumper->Dump([\@input, \%hash], [qw(*input *hash)]);

            __END__

            I could have (should have) made the loop body be the single line:
            push @{$hash{$key} ||= []}, $val;

            I hope that make sense. The Data::Dumper library is quite handy to
            do quick views of data structures when they grow beyond simple arrays
            and hashes. You might want to check out List::MoreUtils (and
            List::Util) for a number of useful manipulations of lists (aka, arrays).

            -Rob

            Rob Biedenharn http://agileconsultingllc.com
            Rob@...
          • jslay77
            ... Awesome thanks for the corrections. I posted that as soon as it worked, and forgot to take some stuff out, and double check it. :) I appreciate the help!
            Message 5 of 5 , Feb 7, 2007
              --- In perl-beginner@yahoogroups.com, Rob Biedenharn <Rob@...> wrote:
              >
              > On Feb 7, 2007, at 7:36 PM, jslay77 wrote:
              > > --- In perl-beginner@yahoogroups.com, Rob Biedenharn <Rob@> wrote:
              > >> On Feb 7, 2007, at 10:58 AM, jslay77 wrote:
              > >>> I hope this is the appropriate forum to ask this question.
              > >>>
              > >>> assume I have a list like this:
              > >>>
              > >>> @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
              > >>> 'hostname10', '2', 'hostname11', '3', 'hostname12');
              > >>>
              > >>> I want to turn this list into a hash of anonymous arrays...something
              > >>> like this I guess.
              > >>>
              > >>> %hash = (
              > >>> '1' => ['hostname1', 'hostname2', 'hostname3'],
              > >>> '2' => ['hostname10', 'hostname11'],
              > >>> '3' => ['hostname12'],
              > >>> );
              > >>>
              > >>>
              > >>> :)
              > >>>
              > >>> I hope I explained that appropriately.
              > >>> regards,
              > >>> J
              > >>
              > >> Why don't you post some code showing your attempt and then we can
              > >> help you if it doesn't do what you expect? Here's a hint, to
              > >> initialize a hash element with an empty array if it doesn't already
              > >> have a value, you can do this:
              > >>
              > >> $hash{$key} ||= [];
              > >>
              > >> I made a subroutine "array_to_hash" taking a list of values and
              > >> returning a hash. My little script also used
              > >> List::MoreUtils::natatime to get the pairs from the array, but that's
              > >> not the only way. I also used Data::Dumper to produce the output to
              > >> visually check the result like this:
              > >>
              > >>
              > >> @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
              > >> 'hostname10', '2', 'hostname11', '3', 'hostname12');
              > >>
              > >> my %hash = array_to_hash @input;
              > >>
              > >> print Data::Dumper->Dump([\@input, \%hash], [qw(*input *hash)]);
              > >>
              > >>
              > >> -Rob
              > >>
              > >> Rob Biedenharn http://agileconsultingllc.com
              > >> Rob@
              > >>
              > >
              > > Rob,
              > >
              > > Thanks for the quick response...and your $hash{$key} ||=[] hint :)
              > >
              > > I actually got around this whole thing by retrieving my data
              > > differently from DBD::Oracle,
              > > however I was still intrigued at the problem...I believe I figured
              > > it out with your help.
              > >
              > > This does what I was looking for, however would there be a better way?
              > >
              > > @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3',
              > > '2', 'hostname10', '2',
              > > 'hostname11', '3', 'hostname12');
              > > my %hash;
              > >
              > > my %seen;
              > You don't need this...
              >
              > > my $key;
              > You haven't used this...
              >
              > But you don't initialize $i (which tells me that you aren't using the
              > -w option)
              >
              > > for (@input; $i <= $#input; $i += 2) {
              > Should be < not <=, but you get lucky since you're incrementing by 2
              > > if (! $seen{$input[$i]}++ ) {
              > > $hash{$input[$i]} ||= ["$input[$i + 1]"];
              > Unless you mean to stringify the values, you don't need the quotes
              > just like you don't need them in the push.
              > > } else {
              > > push @{$hash{$input[$i]}}, $input[$i + 1];
              > > next;
              > > }
              > > }
              >
              > Simplifying and you get (after really using the hint ;-)
              > for (my $i = 0; $i < $#input; $i += 2) {
              > push @{$hash{$input[$i]} ||= []}, $input[$i + 1];
              > }
              >
              > > foreach (sort keys %hash) {
              > > print "$_ --> @{$hash{$_}}\n";
              > > }
              >
              > And for completeness now that you've done your version. Here's mine:
              >
              > #!/usr/bin/env perl -w
              > use List::MoreUtils qw(natatime);
              > use Data::Dumper;
              >
              > sub array_to_hash {
              > my @args = @_;
              > my %hash;
              >
              > my $iter = natatime 2, @args;
              > while (my ($key, $val) = $iter->()) {
              > $hash{$key} ||= [];
              > push @{$hash{$key}}, $val;
              > }
              > return %hash;
              > }
              >
              > @input = ('1', 'hostname1', '1', 'hostname2', '1', 'hostname3', '2',
              > 'hostname10', '2', 'hostname11', '3', 'hostname12');
              > my %hash = array_to_hash @input;
              >
              > print Data::Dumper->Dump([\@input, \%hash], [qw(*input *hash)]);
              >
              > __END__
              >
              > I could have (should have) made the loop body be the single line:
              > push @{$hash{$key} ||= []}, $val;
              >
              > I hope that make sense. The Data::Dumper library is quite handy to
              > do quick views of data structures when they grow beyond simple arrays
              > and hashes. You might want to check out List::MoreUtils (and
              > List::Util) for a number of useful manipulations of lists (aka, arrays).
              >
              > -Rob
              >
              > Rob Biedenharn http://agileconsultingllc.com
              > Rob@...
              >


              Awesome thanks for the corrections. I posted that as soon as it worked, and forgot to
              take some stuff out, and double check it. :)

              I appreciate the help!
            Your message has been successfully submitted and would be delivered to recipients shortly.