sub make_list { my %opt = @_; my $file = $opt{file} && ref($opt{file}) eq 'ARRAY' ? data_file(@{$opt{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_headers]; 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; } #### print DDumper make_list( file => $Artifacts, headings => ['+'] ); { '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' ] } #### print DDumper make_list( file => $programs ); { Adobe => 'www.adobe.com/downloads', CCleaner => 'www.piriform.com/ccleaner', 'Cerulean Studios TrillianAstra' => 'www.trillian.im', Chrome => 'www.google.com/chrome', Debian => 'www.debian.org', Defraggler => 'www.piriform.com/defraggler', 'Ever Changing Book of Names' => 'ebon.pyorre.net', FileZilla => 'filezilla-project.org', Firefox => 'www.mozilla.com/en-US/firefox', 'Flash Player' => 'get.adobe.com/flashplayer', Geany => 'www.geany.org', Google => 'www.google.com', HexChat => 'hexchat.github.io', KDE => 'www.kde.org', LibreOffice => 'www.libreoffice.org', Mozilla => 'www.mozilla.org', 'Notepad++' => 'notepad-plus.sourceforge.net/uk/site.htm', Opera => 'www.opera.com', Piriform => 'www.piriform.com', QuickTime => 'www.apple.com/quicktime/download', RarLab => 'www.rarlab.com', Reader => 'get.adobe.com/reader', Safari => 'www.apple.com/safari/download', 'Strawberry Perl' => 'strawberryperl.com', TableSmith => 'mythosa.net/wiki/pmwiki.php?n=Main.TableSmith', 'The Apache Software Foundation' => 'www.apache.org', 'VLC media player' => 'www.videolan.org/vlc/index.html', VideoLAN => 'www.videolan.org', grepWin => 'tools.tortoisesvn.net/grepWin.html', } #### print DDumper make_list_2( file => $BBSs, headings => [qw(name domain ip site)] ); { Abyss => { domain => 'abyss.monad.net', ip => '204.97.16.51', name => 'Abyss', site => undef }, 'Aloha BBS' => { domain => 'alohabbs.org.mx', ip => undef, name => 'Aloha BBS', site => undef }, Apocalypse => { domain => undef, ip => '208.215.35.204', name => 'Apocalypse', site => undef }, Astro => { domain => 'astro.sci.muni.cz', ip => undef, name => 'Astro', site => 'astro.sci.muni.cz' }, Atlantis => { domain => 'bbs.resus.univ-mrs.fr', ip => '139.124.29.1', name => 'Atlantis', site => undef }, }