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

Re: Transforming a list into a hash of arrays

Expand Messages
  • 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 1 of 5 , Feb 7, 2007
    • 0 Attachment
      --- 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 2 of 5 , Feb 7, 2007
      • 0 Attachment
        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 3 of 5 , Feb 7, 2007
        • 0 Attachment
          --- 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.