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

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

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