in reply to Creating a Multi Level Hash from CSV

Something like this? I faked an input file because you did not include a valid input file.

#!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11132513 use warnings; my %hash; while( <DATA> ) { my ( $top, @rest ) = split /,|\n/; # FIXME faking CSV for testing $hash{$top} = chain(@rest); } use Data::Dump 'dd'; dd \%hash; sub chain { return @_ > 1 ? { shift() => chain(@_) } : shift(); } __DATA__ a,b,c,d,e f,g,h,i,j xx,yy,zz this,is,a,strange,type,of,data,organization

Outputs:

{ a => { b => { c => { d => "e" } } }, f => { g => { h => { i => "j" } } }, this => { is => { a => { strange => { type => { of => { data => "organizatio +n" } } } }, }, }, xx => { yy => "zz" }, }

Replies are listed 'Best First'.
Re^2: Creating a Multi Level Hash from CSV
by Fletch (Chancellor) on May 14, 2021 at 12:43 UTC

    Or you could do it functionally rather than explicit recursion using List::Util's reduce (not that that's likely to be of any help to trolls who're unfamiliar with a bog simple recursive sub . . .).

    ## (reduce #(hash-map %2 %1) 1 (reverse [:foo :bar :baz :quux])) use List::Util qw( reduce ); use Data::Dumper qw( Dumper ); my $hash = reduce { +{ $b => $a } } 1, reverse( qw( foo bar baz quux ) + ); say Dumper( $hash ); __END__ $VAR1 = { 'foo' => { 'bar' => { 'baz' => { 'quux' => '1' } } } };

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re^2: Creating a Multi Level Hash from CSV
by workInProgress12 (Novice) on May 13, 2021 at 17:18 UTC
    This was so helpful, thank you so much I've really been struggling. I was wondering if you could explain the sub chain{} function? I'm not at all sure what you're doing there, but it works! Also do you have any advice as to what I should do if I want to remove the first row so the header doesn't do what the rest of the hash is doing. Again, really appreciate all your help.
      ... explain the sub chain{} function ...

      The"Perl Magick" here is recursion; it is not peculiar to Perl in any way.

      sub chain { return @_ > 1 ? { shift() => chain(@_) } : shift(); }
      If there are two or more items in the @_ function argument array (@_ > 1), { shift() => chain(@_) } executes. shift takes the top argument off of @_ and makes it a hash key with the value of whatever the call to chain(@_) returns. Note that chain(@_) is called with whatever remains in the @_ array after one item has been removed by the shift call. This key/value pair is then returned within an anonymous hash reference.

      If there are fewer than two items in the @_ array, the call to chain(@_) simply returns the top item in the array. Note that this does not "properly" handle the case in which the @_ array is empty. What is "proper" handling in this case (if it can even arise)? Only you can figure this out.

      Win8 Strawberry 5.8.9.5 (32) Thu 05/13/2021 15:26:20 C:\@Work\Perl\monks >perl -Mstrict -Mwarnings my %hash; # my ( $top, @rest ) = split /,|\n/; # FIXME faking CSV for testing my ($top, @rest) = qw(foo); $hash{$top} = chain(@rest); use Data::Dump 'dd'; dd \%hash; sub chain { return @_ > 1 ? { shift() => chain(@_) } : shift(); } ^Z { foo => undef }

      ... remove the first row so the header doesn't do what the rest of the hash is doing.

      One might do the following:
          open(my $input, '<:utf8',"input.csv") or die;

          <$input>;  # read and discard one line/record
      (I think Text::CSV can do this for you (it does just about everything else :), but you'll have to check for yourself.)


      Give a man a fish:  <%-{-{-{-<

    A reply falls below the community's threshold of quality. You may see it by logging in.