2

Here is the code, I know it is not perfect perl. If you have insight on how I an do better let me know. My main question is how would I print out the arrays without using Data::Dumper?

#!/usr/bin/perl
use Data::Dumper qw(Dumper);

use strict;
use warnings;

open(MYFILE, "<", "move_headers.txt") or die "ERROR: $!";

#First split the list of files and the headers apart
my @files;
my @headers;
my @file_list = <MYFILE>;
foreach my $source_parts (@file_list) {
  chomp($source_parts);
  my @parts = split(/:/, $source_parts);
  unshift(@files, $parts[0]);
  unshift(@headers, $parts[1]);
}

# Next get a list of unique headers
my @unique_files;
foreach my $item (@files) {
  my $found = 0;
  foreach my $i (@unique_files) {
      if ($i eq $item) {
        $found = 1;
        last;
      }
  }
  if (!$found) {
    unshift @unique_files, $item;
  }
}
@unique_files = sort(@unique_files);

# Now collect the headers is a list per file
my %hash_table;
for (my $i = 0; $i < @files; $i++) {
  unshift @{ $hash_table{"$files[$i]"} }, "$headers[$i]";
}

# Process the list with regex
while ((my $key, my $value) = each %hash_table) {
  if (ref($value) eq "ARRAY") {
    print "$value", "\n";
  }
}
Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162
Matthew Hoggan
  • 7,402
  • 16
  • 75
  • 140
  • Can you use another module from CPAN instead of Data::Dumper? – stevenl Jan 05 '12 at 00:48
  • I have to move a set of headers across 100+ files to the bottom of the #include files in a C++/C program. They must be included last because of namespace conflicts between C and c++ files. There is no way I am going to do this by hand. So I have a hash of files with the headers in a list that need to be moved to the bottom. – Matthew Hoggan Jan 05 '12 at 00:57
  • Re "If you have insight on how I an do better let me know.", this belongs on [http://codereview.stackexchange.com/](http://codereview.stackexchange.com/) – ikegami Jan 05 '12 at 01:02
  • Point taken, that was more of a disclaimer to keep perl enthusiasts focused on the problem. – Matthew Hoggan Jan 05 '12 at 01:06

3 Answers3

7

The Perl documentation has a tutorial on "Printing of a HASH OF ARRAYS" (without using Data::Dumper)

perldoc perldsc

toolic
  • 57,801
  • 17
  • 75
  • 117
4

An alternative to using Data::Dumper is to use Data::Printer:

use Data::Printer;
p $value;

You can also use this to customise the format of the output. E.g. you can have it all in a single line without the indexes (see the documentation for more options):

use Data::Printer {
    index     => 0,
    multiline => 0,
};
p $value;

Also, as a suggestion for getting unique files, put the elements into a a hash:

my %unique;
@unique{ @files } = @files;
my @unique_files = sort keys %unique;

Actually, you could even skip that step and put everything into %hash_table in one pass:

my %hash_table;
foreach my $source_parts (@file_list) {
    chomp($source_parts);
    my @parts = split(/:/, $source_parts);
    unshift @{ $hash_table{$parts[0]} }, $parts[1];  
}
stevenl
  • 6,736
  • 26
  • 33
4

You're doing a couple things the hard way. First, a hash will already uniqify its keys, so you don't need the loop that does that. It appears that you're building a hash of files, with the values meant to be the headers found in those files. The input data is "filename:header", one per line. (You could use a hash of hashes, since the headers may need uniquifying, but let's let that go for now.)

use strict;
use warnings;
open my $files_and_headers, "<", "move_headers.txt" or die "Can't open move_headers: $!\n";

my %headers_for_file;
while (defined(my $line = <$files_and_headers> )) {
        chomp $line;
        my($file, $header) = split /:/, $line, 2;
        push @{ $headers_for_file{$file} }, $header;
}

# Print the arrays for each file:
foreach my $file (keys %headers_for_file) {
    print "$file: @{ $headers_for_file{$file}}\n";
}

We're letting Perl do a chunk of the work here:

  1. If we add keys to a hash, they're always unique.
  2. If we interpolate an array into a print statement, Perl adds spaces between them.
  3. If we push onto an empty hash element, Perl automatically puts an empty anonymous array in the element and then pushes onto that.
Joe McMahon
  • 3,266
  • 21
  • 33