http://qs1969.pair.com?node_id=744486

Angharad has asked for the wisdom of the Perl Monks concerning the following question:

I have a number of files with data that is presented like this (only much larger).
1 G 2 F 4 H 8 T
5 Y 6 R 7 E 8 I
2 H 4 T 3 G 8 R
I would like to create a new file containing all the information in these files and format it as follows.
1 G 5 Y 2 H 2 F 6 R 4 T 4 H 7 E 3 G 8 T 8 I 8 R
Could someone please give me a few pointers as to how to do this? I guess I could open all the files, store them in separate hashes and then print them out somehow? Thanks in advance

Replies are listed 'Best First'.
Re: making 3 files into one
by ikegami (Patriarch) on Feb 17, 2009 at 17:45 UTC
    Is the relation between "1 G" and "5 Y" simply the position in the file? Then
    my @qfns; my @fhs; for my $qfn (@qfns) { open(my $fh, '<', $qfn) or die("Can't open \"$qfn\": $!\n"); push @fhs, $fh; } for (;;) { my @lines; my $all_done = 1; my $some_done = 0; for my $fh (@fhs) { push @lines, my $line = <$fh>; if (defined($line)) { $some_done = 1; } else { $all_done = 0; } } exit(0) if $all_done; die("Premature eof\n") if $some_done; chomp @lines; print(join(' ', @lines), "\n"); }
Re: making 3 files into one
by toolic (Bishop) on Feb 17, 2009 at 17:45 UTC
    If on unix, you could use paste:
    paste file1 file2 file3 > file.out
Re: making 3 files into one
by Lawliet (Curate) on Feb 17, 2009 at 17:43 UTC

    I would open each file and store them in separate arrays where each element of an array is a single line in the corresponding file. Open a fourth file for writing and use a for loop to print each element of each array.

    for (my $i = 0; $i < $#file; $i++) { print FILE "$file[$i] $file2[$i] $file3[$i]\n"; }

    Or something~

    And you didn't even know bears could type.

Re: making 3 files into one
by CountZero (Bishop) on Feb 17, 2009 at 22:26 UTC
    Will handle arbitrarily large files with minimal memory use:
    use strict; open my $FILE1, '<', 'my/input/file1' or die "Could not open FILE1: $! +"; open my $FILE2, '<', 'my/input/file2' or die "Could not open FILE2: $! +"; open my $FILE3, '<', 'my/input/file3' or die "Could not open FILE3: $! +";; open my $FILE4, '>', 'my/output/file' or die "Could not open FILE4: $! +"; while (my $file1 = <$FILE1>) { my $file2 = <$FILE2>; my $file3 = <$FILE3>; chomp $file1; chomp $file2; print $FILE4, "$file1 $file2 $file3" or die "Could not print to FI +LE4"; }
    Update: We assume that each file has the same number of lines.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: making 3 files into one
by skywalker (Beadle) on Feb 17, 2009 at 18:05 UTC

    Why dont you slurp each file into any array then use a for loop to print 1 record from each file at a time

    quick bit of code

    use strict; my @file1 = ("1 G","2 F","4 H","8 T"); my @file2 = ("5 Y","6 R","7 E","8 I"); my @file3 = ("2 H","4 T","3 G","8 R"); my $largest_array = scalar @file1; $largest_array = scalar @file2 if(scalar @file2 > $largest_array); $largest_array = scalar @file3 if(scalar @file3 > $largest_array); my @array =(\@file1,\@file2,\@file3); for (my $ctr =0;$ctr <= $largest_array;$ctr++){ print $array[0][$ctr] if($ctr <= scalar @{$array[0]}); print $array[1][$ctr] if($ctr <= scalar @{$array[1]}); print $array[2][$ctr] if($ctr <= scalar @{$array[2]}); print "\n"; } print "\n\nComplete";
Re: making 3 files into one
by GrandFather (Saint) on Feb 18, 2009 at 03:30 UTC

    A somewhat generalized solution to the problem allows a arbitrary number of files to be handled:

    use strict; use warnings; my $file1 = <<'END_FILE'; 1 G 2 F 4 H 8 T END_FILE my $file2 = <<'END_FILE'; 5 Y 6 R 7 E 8 I END_FILE my $file3 = <<'END_FILE'; 2 H 4 T 3 G 8 R END_FILE my @fileHandles; open $fileHandles[@fileHandles], '<', $_ for \$file1, \$file2, \$file3 +; printLines (@fileHandles); close $_ for @fileHandles; sub printLines { my @fileHandles = @_; my $moreLines = 1; while ($moreLines) { my $line = ''; for my $fh (@fileHandles) { $line .= ' ' if length $line; $line .= <$fh> or return; chomp $line; } print "$line\n"; $line = ''; } }

    Prints:

    1 G 5 Y 2 H 2 F 6 R 4 T 4 H 7 E 3 G 8 T 8 I 8 R

    True laziness is hard work
Re: making 3 files into one
by Anonymous Monk on Feb 18, 2009 at 08:49 UTC
    hi friend, Try out this one...
    opendir(DIR,'.') or die $!; @read=readdir(DIR); close(DIR); foreach(@read){ if($_ =~/^f\d.txt$/){ push(@read1,$_); } } @read2=sort(@read1); foreach (@read2){ open(FILE,$_) or die $!; push(@file,<FILE>); close(FILE); push(@file,"LINE\n"); } $string=join('',@file); $string=~s/\n/#/g; ($val1,$val2,$val3)=split('LINE#',$string); @val1=split('#',$val1); @val2=split('#',$val2); @val3=split('#',$val3); foreach $i(0 .. scalar @val1){ print "$val1[$i]\t$val2[$i]\t$val3[$i]\n"; }