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

Re: [PBML] Re: Transforming a list into a hash of arrays

Expand Messages
  • 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 1 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 2 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.