http://www.perlmonks.org?node_id=1192522


in reply to Can Text::CSV_XS return key-value pairs?

Something like this?

use 5.18.2; use warnings; use Data::Peek; use Text::CSV_XS qw(csv); my $file = "pm-1192516.csv"; sub make_list_2 { my %opt = @_; my $headers = $opt{headings}; my %foo; my $list = csv ( in => $opt{file}, headers => $headers, sep_char => "|", quote_char => undef, empty_is_undef => 1, allow_whitespace => 1, auto_diag => 1, on_in => sub { push @{$foo{$_{item}}}, split m/;\s*/ => $_{"seen in+"} }, ); return \%foo; } DDumper make_list_2 (file => $file, headings => [ "item", "seen in+" ] +);

->

{ 'Ark of the Covenant' => [ 'Raides of the Lost Ark', 'The Librarian: Quest for the Spear' ], 'Book or Key of Soloman' => [ 'The Librarian: Return to King Soloman\'s Mines', 'Season of the Witch' ], 'Crystal Skull' => [ 'Stargate SG-1, Crystal Skull', 'The Librarian: Return to King Soloman\'s Mines', 'Indiana Jones and the Kingdom of the Crystal Skull' ], 'Doc Brown\'s Delorean' => [ 'Back to the Future', 'Back to the Future Part II', 'Back to the Future Part III', 'The Librarians, And the Final Curtain' ], Excalibur => [ 'Excalibur', 'The Last Legion', 'The Librarian: Quest for the Spear' ], 'H.G. Wells\' Time Machine' => [ 'The Librarians', 'Warehouse 13' ], 'Holy Grail' => [ 'Indiana Jones and the Last Crusade', 'The Librarian: Quest for the Spear' ], Necronomicon => [ 'H.P. Lovecraft' ], 'Pandora\'s Box' => [ 'Warehouse 13', 'The Librarian: Quest for the Spear' ], 'Spear of Destiny' => [ 'The Librarian: Quest for the Spear', 'Hellboy', 'Constantine' ], TARDIS => [ 'Doctor Who', 'The Sarah Jane Adventures', 'The Librarians, And the Final Curtain' ] }

Enjoy, Have FUN! H.Merijn

Replies are listed 'Best First'.
Re^2: Can Text::CSV_XS return key-value pairs?
by Lady_Aleena (Priest) on Jun 11, 2017 at 23:32 UTC

    Tux, can I add that to what I already have? Also, the value will not always be split. So can the value be first put through the filters then go to the on_in? And if this needs to use an additional hash, then how do I get everything to use the outside hash, the one you called %foo?

    sub make_list { my (%opt) = @_; my $file = $opt{file} && ref($opt{file}) eq 'ARRAY' ? data_file(@{$o +pt{file}}) : $opt{file}; my $headers = $opt{'headings'} ? $opt{'headings'} : ['heading']; my $filters; for my $header (@$headers) { if ($header =~ s/\+$//) { $filters->{$header} = sub { $_ = [split(/;\s*/, $_)]; $_ }; } } my $list = csv ( in => $file, headers => $headers, key => $opt{key} ? $headers->[0] : undef, filter => $filters, sep_char => '|', quote_char => undef, empty_is_undef => 1, allow_whitespace => 1, auto_diag => 1, ); return $list; }

    I did not want to include the code I am trying to replace with an all in one, but it looks like I have to.

    No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
    Lady Aleena

      Like this then? (only requirement is to have "item" a required field

      use 5.18.2; use warnings; use Data::Peek; use Text::CSV_XS qw(csv); my $file = "pm-1192516.csv"; sub make_list { my %opt = @_; my %plus; my @head = map { s/\+$// && $plus{$_}++; $_ } @{$opt{headings}}; my %foo; my $list = csv ( in => $opt{file}, headers => \@head, sep_char => "|", quote_char => undef, empty_is_undef => 1, allow_whitespace => 1, auto_diag => 1, on_in => sub { foreach my $f (@head) { $f eq "item" and next; push @{$foo{$_{item}}{$f}}, $plus{$f} ? split m/;\s*/ +=> $_{$f} : $_{$f}; } }, ); return \%foo; } DDumper make_list (file => $file, headings => [ "item", "seen in+" ]);

      ->

      { 'Ark of the Covenant' => { 'seen in' => [ 'Raides of the Lost Ark', 'The Librarian: Quest for the Spear' ] }, 'Book or Key of Soloman' => { 'seen in' => [ 'The Librarian: Return to King Soloman\'s Mines', 'Season of the Witch' ] }, 'Crystal Skull' => { 'seen in' => [ 'Stargate SG-1, Crystal Skull', 'The Librarian: Return to King Soloman\'s Mines', 'Indiana Jones and the Kingdom of the Crystal Skull' ] }, 'Doc Brown\'s Delorean' => { 'seen in' => [ 'Back to the Future', 'Back to the Future Part II', 'Back to the Future Part III', 'The Librarians, And the Final Curtain' ] }, Excalibur => { 'seen in' => [ 'Excalibur', 'The Last Legion', 'The Librarian: Quest for the Spear' ] }, 'H.G. Wells\' Time Machine' => { 'seen in' => [ 'The Librarians', 'Warehouse 13' ] }, 'Holy Grail' => { 'seen in' => [ 'Indiana Jones and the Last Crusade', 'The Librarian: Quest for the Spear' ] }, Necronomicon => { 'seen in' => [ 'H.P. Lovecraft' ] }, 'Pandora\'s Box' => { 'seen in' => [ 'Warehouse 13', 'The Librarian: Quest for the Spear' ] }, 'Spear of Destiny' => { 'seen in' => [ 'The Librarian: Quest for the Spear', 'Hellboy', 'Constantine' ] }, TARDIS => { 'seen in' => [ 'Doctor Who', 'The Sarah Jane Adventures', 'The Librarians, And the Final Curtain' ] } }

      Enjoy, Have FUN! H.Merijn

        More like the following without the need of a required first field. I took out the push since it was making every field an array ref. Also, this does both a hash and hash of hashes. Now to get arrays of hashes, and I'd have my all in one. 8)

        It took me this long to figure all of this out, but I had a sick cat to deal with too. My sick cat takes precedence over my perl code.

        sub make_list { my %opt = @_; my $file = $opt{file} && ref($opt{file}) eq 'ARRAY' ? data_file(@{$o +pt{file}}) : $opt{file}; my $raw_headers = $opt{'headings'} ? $opt{'headings'} : ['heading']; unshift @$raw_headers, 'key' if scalar @$raw_headers == 1; my %exapansions; my $headers = [map { s/\+$// && $exapansions{$_}++; $_ } @$raw_heade +rs]; my %list; my $csv = csv ( in => $file, headers => $headers, sep_char => '|', quote_char => undef, empty_is_undef => 1, allow_whitespace => 1, auto_diag => 1, on_in => sub { for my $header (@$headers) { if (scalar @$headers == 2) { $header eq $headers->[0] and next; $list{$_{$headers->[0]}} = $exapansions{$header} ? [split(m/ +;\s*/, $_{$header})] : $_{$header}; } else { $list{$_{$headers->[0]}}{$header} = $exapansions{$header} ? +[split(m/;\s*/, $_{$header})] : $_{$header}; } } } ); return \%list; }

        Gives me ...

        And this (file)...

        And even this (file)...

        No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
        Lady Aleena