merging two files with similar columns - perl

I have a two tab separated files that I need to align together. for example:
File 1: File 2:
AAA 123 BBB 345
BBB 345 CCC 333
CCC 333 DDD 444
(These are large files, potentially thousands of lines!)
What I would like to do is to have the output look like this:
AAA 123
BBB 345 BBB 345
CCC 333 CCC 333
DDD 444
Preferably I would like to do this in perl, but not sure how. any help would be greatly appreaciated.

If its just about making a data structure, this can be quite easy.
#!/usr/bin/env perl
# usage: script.pl file1 file2 ...
use strict;
use warnings;
my %data;
while (<>) {
chomp;
my ($key, $value) = split;
push #{$data{$key}}, $value;
}
use Data::Dumper;
print Dumper \%data;
You can then output in any format you like. If its really about using the files exactly as they are, then its a little bit more tricky.

Assuming the files are sorted,
sub get {
my ($fh) = #_;
my $line = <$fh>;
return () if !defined($line);
return split(' ', $line);
}
my ($key1, $val1) = get($fh1);
my ($key2, $val2) = get($fh2);
while (defined($key1) && defined($key2)) {
if ($key1 lt $key2) {
print(join("\t", $key1, $val1), "\n");
($key1, $val1) = get($fh1);
}
elsif ($key1 gt $key2) {
print(join("\t", '', '', $key2, $val2), "\n");
($key2, $val2) = get($fh2);
}
else {
print(join("\t", $key1, $val1, $key2, $val2), "\n");
($key1, $val1) = get($fh1);
($key2, $val2) = get($fh2);
}
}
while (defined($key1)) {
print(join("\t", $key1, $val1), "\n");
($key1, $val1) = get($fh1);
}
while (defined($key2)) {
print(join("\t", '', '', $key1, $val1), "\n");
($key2, $val2) = get($fh2);
}

Similar to Joel Berger's answer, but this approach allows to you keep track of whether files did or did not contain a given key:
my %data;
while (my $line = <>){
chomp $line;
my ($k) = $line =~ /^(\S+)/;
$data{$k}{line} = $line;
$data{$k}{$ARGV} = 1;
}
use Data::Dumper;
print Dumper(\%data);
Output:
$VAR1 = {
'CCC' => {
'other.dat' => 1,
'data.dat' => 1,
'line' => 'CCC 333'
},
'BBB' => {
'other.dat' => 1,
'data.dat' => 1,
'line' => 'BBB 345'
},
'DDD' => {
'other.dat' => 1,
'line' => 'DDD 444'
},
'AAA' => {
'data.dat' => 1,
'line' => 'AAA 123'
}
};

As ikegami mentioned, it assumes that the files' contents are arranged as shown in your example.
use strict;
use warnings;
open my $file1, '<file1.txt' or die $!;
open my $file2, '<file2.txt' or die $!;
my $file1_line = <$file1>;
print $file1_line;
while ( my $file2_line = <$file2> ) {
if( defined( $file1_line = <$file1> ) ) {
chomp $file1_line;
print $file1_line;
}
my $tabs = $file1_line ? "\t" : "\t\t";
print "$tabs$file2_line";
}
close $file1;
close $file2;
Reviewing your example, you show some identical key/value pairs in both files. Given this, it looks like you want to show the pair(s) unique to file 1, unique to file 2, and show the common pairs. If this is the case (and you're not trying to match the files' pairs by either keys or values), you can use List::Compare:
use strict;
use warnings;
use List::Compare;
open my $file1, '<file1.txt' or die $!;
my #file1 = <$file1>;
close $file1;
open my $file2, '<file2.txt' or die $!;
my #file2 = <$file2>;
close $file2;
my $lc = List::Compare->new(\#file1, \#file2);
my #file1Only = $lc->get_Lonly; # L(eft array)only
for(#file1Only) { print }
my #bothFiles = $lc->get_intersection;
for(#bothFiles) { chomp; print "$_\t$_\n" }
my #file2Only = $lc->get_Ronly; # R(ight array)only
for(#file2Only) { print "\t\t$_" }

Related

reading text file and writing to two dimensional array in perl? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use open ':encoding(UTF-8)', ':std';
use List::Util qw( sum );
my $filename = 'data1.txt';
open(my $fh, '<:encoding(UTF-8)', $filename)
or die "Could not open file '$filename' $!";
while (my $row = <$fh>) {
chomp $row;
print "$row\n";
}
my $filename2 = 'data2.txt';
open(my $fh2, '<:encoding(UTF-8)', $filename2)
or die "Could not open file '$filename2' $!";
while (my $row = <$fh2>) {
chomp $row;
print "$row\n";
}
my #last = ();
my %grades = (
Ahmet => {
quiz1 => 97,
quiz2 => 67,
quiz3 => 93,
},
Su => {
quiz1 => 88,
quiz2 => 82,
quiz3 => 99,
});
my %sum;
for my $name (keys %grades){
$sum{$name} = sum(values %{ $grades{$name} });
}
for my $name (sort { $sum{$a} <=> $sum{$b} } keys %sum){
push #last, "$name: $sum{$name}\n";
}
my %grades2 = (
Bugra => {
quiz1 => 33,
quiz2 => 41,
quiz3 => 59,
},
Lale => {
quiz1 => 79,
quiz2 => 31,
quiz3 => 62,
},
);
my %sum2;
for my $name (keys %grades2){
$sum2{$name} = sum(values %{ $grades2{$name} });
}
for my $name (sort { $sum2{$a} <=> $sum2{$b} } keys %sum2){
push #last, "$name: $sum2{$name}\n";
}
my #last1 = sort { lc($a) cmp lc($b) } #last;
print #last1;
This is my code. I want to take values from a text file something like ( marry 10 65 23) and write to a two dimensional array. I managed array separately end of the read text file it has to be seen like grade1 and grade2 for data1.txt and data2.txt. I can pull the values but I couldn't write to two dimensional array. Also result is correct.
I read your question as How do I populate the hashes %grade1 and %grade2 from the files data1.txt and data2.txt?
I also assume that your files data1.txt and data2.txt have the following structure (whitespace separated):
marry 10 65 23
john 20 30 40
I suggest to write a function that takes the filename as paramater and returns a reference to a populated hash:
sub read_grades_from_file
{
my $filename = shift;
my $result = {};
open( my $fh, '<:encoding(UTF-8)', $filename )
or die "Could not open file '$filename' $!\n";
while ( my $row = <$fh> ) {
next unless $row =~ /\S/; # skip empty lines
my ( $name, $quiz1, $quiz2, $quiz3 ) = split( ' ', $row );
$result->{$name} = {
quiz1 => $quiz1,
quiz2 => $quiz2,
quiz3 => $quiz3,
};
}
close($fh);
return $result;
}
The function is used as follows:
my $result = read_grades_from_file('data1.txt'); # returns hashref
my %grade1 = %{$result}; # dereference $result to make it a hash
$result = read_grades_from_file('data2.txt');
my %grade2 = %{$result};
The result of read_grades_from_file is a reference to a hash so it has to be de-referenced and then assigned to %grade. Thus the two steps.
Perhaps the data structures you are using are overly complex. You probably only need a single %grades hash, for example.
The following will take data from space- or tab-separated records from both two input files - ignoring comments or empty lines.
my %grades;
while (1) {
my $row1 = <$data1>;
my $row2 = <$data2>;
last unless (defined $row1 or defined $row2);
chomp ($row1, $row2);
if (defined $row1 and $row1 !~ /(^#|^$)/) {
my ($name, #quizzes) = split /[ \t]/, $row1, 4;
$grades{$name}{'grades1'} = sum(#quizzes);
}
if (defined $row2 and $row1 !~ /(^#|^$)/) {
my ($name, #quizzes) = split /[ \t]/, $row2, 4;
$grades{$name}{'grades2'} = sum(#quizzes);
}
}
To print to STDOUT, you could try the following.
print "Name\tMarks 1\tMarks 2", $/;
for (keys %grades) {
my $name = $grades{$_};
print $_, "\t", $name->{grades1} || '?', "\t", $name->{grades2} || '?', "\t", $/;
}
With data1.txt as
# Grades
Bugra 33 41 59
Mary 10 65 23
Lale 79 31 62
and data2.txt as
# Grades 2
Bugra 49 32 57
Lale 79 31 62
Peter 21 34 42
the output is shown below.
Name Marks 1 Marks 2
Peter ? 97
Lale 172 172
Bugra 133 138
Mary 98 ?
(A '?' indicates that no record exists for the specified student in one of the two input files.)

Using perl to cycle through a list of values (x) and compare to another file with value ranges

I have two files. One file has a list of values like so
NC_SNPStest.txt
250
275
375
The other file has space delimited information. Column one is the first value of a range, Column two has the second value of a range, Column 5 has the name of the range, and Column eight has what acts on that range.
promoterstest.txt
20 100 yaaX F yaaX 5147 5.34 Sigma70 99
200 300 yaaA R yaaAp1 6482 6.54 Sigma70 35
350 400 yaaA R yaaAp2 6498 2.86 Sigma70 51
I am trying to write a script that takes the first line from file 1 and then parses file 2 line by line to see if that value falls in the range is between the first two columns.
When the first match is found, I want to print the value from file 1 and then the values in file 2 for columns 5 and 8 from the line with the match. If no match is found in File 2 then just print the value from File 1 and move on.
It seems like it should be a simple enough task but I'm having an issue cycling though both files.
This is what I have written:
#!/usr/bin/perl
use warnings;
use strict;
open my $PromoterFile, '<', 'promoterstest.txt' or die $!;
open my $SNPSFile, '<', 'NC_SNPtest.txt' or die $!;
open (FILE, ">PromoterMatchtest.txt");
while (my $SNPS = <$SNPSFile>) {
chomp ($SNPS);
while (my $Cord = <$PromoterFile>) {
chomp ($Cord);
my #CordFile =split(/\s/, $Cord);
my $Lend = $CordFile[0];
my $Rend = $CordFile[1];
my $Promoter = $CordFile[4];
my $SigmaFactor = $CordFile[7];
foreach $a ($SNPS)
{
if ($a >= $Lend && $a <= $Rend)
{
print FILE "$a\t$CordFile[4]\t$CordFile[7]\n";
}
else
{
print FILE "$a\n";
}
}
}
}
close FILE;
close $PromoterFile;
close $SNPSFile;
exit;
So far my output looks like so:
250
250 yaaAp1 Sigma70
250
Where the first line of file 1 is being called and file 2 is being cycled through. But the else command is being used on each line of file 2 and the script never cycles through the other lines of file 1.
Your problem is you're not resetting your progress through the second file. You read one line from $SNPSFile, check that against ever line in the second file.
But when you start over, you're already at the end of file, so:
while (my $Cord = <$PromoterFile>) {
Doesn't have anything to read.
A quick fix for this would be to add a seek command in there, but that'll make inefficient code. I'd suggest instead reading file 1 into a array, and referencing that instead.
Here's a first draft rewrite that may help.
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
open my $PromoterFile, '<', 'promoterstest.txt' or die $!;
open my $SNPSFile, '<', 'NC_SNPtest.txt' or die $!;
open my $output, ">", "PromoterMatchtest.txt" or die $!;
my #data;
while (<$PromoterFile>) {
chomp;
my #CordFile = split;
my $Lend = $CordFile[0];
my $Rend = $CordFile[1];
my $Promoter = $CordFile[4];
my $SigmaFactor = $CordFile[7];
push(
#data,
{ lend => $CordFile[0],
rend => $CordFile[1],
promoter => $CordFile[4],
sigmafactor => $CordFile[7]
}
);
}
print Dumper \#data;
foreach my $value (<$SNPSFile>) {
chomp $value;
my $found = 0;
foreach my $element (#data) {
if ( $value >= $element->{lend}
and $value <= $element->{rend} )
{
#print "Found $value\n";
print {$output} join( "\t",
$value, $element->{promoter}, $element->{sigmafactor} ),
"\n";
$found++;
last;
}
}
if ( not $found ) {
print {$output} $value,"\n";
}
}
close $output;
close $PromoterFile;
close $SNPSFile;
First - we open file2, read in the stuff in it to an array of hashes. (If any of the elements there are unique, we could key off that instead.)
Then we read through SNPSfile one line at a time, looking for each key - printing it if it exists (at least once, on the first hit) and printing just the key if it doesn't.
This generates the output:
250 yaaAp1 Sigma70
275 yaaAp1 Sigma70
375 yaaAp2 Sigma70
Was that what you were aiming for?
Aside from that 'Dumper' statement which outputs the content of #data as thus:
$VAR1 = [
{
'sigmafactor' => 'Sigma70',
'promoter' => 'yaaX',
'lend' => '20',
'rend' => '100'
},
{
'sigmafactor' => 'Sigma70',
'promoter' => 'yaaAp1',
'rend' => '300',
'lend' => '200'
},
{
'promoter' => 'yaaAp2',
'sigmafactor' => 'Sigma70',
'rend' => '400',
'lend' => '350'
}
];
Here's my take on a programming solution. It's important to
Use lexical file handles and the three-paremeter form of open
Keep to lower-case letters, digits and underscores for local variables
I have also used the autodie pragma to remove the need to test the status of open explicitly, and the first function from the core library List::Util to make the code clearer and more concise
use strict;
use warnings;
use 5.010;
use autodie;
use List::Util 'first';
my #promoters;
{
open my $fh, '<', 'promoterstest.txt';
while ( <$fh> ) {
my #fields = split;
push #promoters, [ #fields[0,1,4,7] ];
}
}
open my $fh, '<', 'NC_SNPStest.txt';
open my $out_fh, '>', 'PromoterMatchtest.txt';
select $out_fh;
while ( <$fh> ) {
my ($num) = split;
my $match = first { $num >= $_->[0] and $num <= $_->[1] } #promoters;
if ( $match ) {
print join("\t", $num, #{$match}[2,3]), "\n";
}
else {
print $num, "\n";
}
}
output
250 yaaAp1 Sigma70
275 yaaAp1 Sigma70
375 yaaAp2 Sigma70

Perl : Unable to write output to file

So I have this code which takes input and output file from command line, then writes a certain output to the output file (Only the relevant portion shown here due to privacy issues):
use strict;
use warnings;
use autodie;
# check that two arguments have been passed
die "usage: $0 input output\n" unless #ARGV == 2;
my $infile = shift;
my $outfile = shift;
open my $in, "<", $infile;
open(DATA, $in);
open my $out, ">", $outfile;
my %DEF = (
I => [ qw( P Pl P.P P.Pl Pl.P Pl.Pl P.P.P P.P.Pl P.Pl.P P.Pl.Pl Pl. +P.P Pl.P.Pl Pl.Pl.P Pl.Pl.Pl ) ],
II => [ qw( E P.E Pl.E P.P.E P.Pl.E Pl.P.E Pl.Pl.E ) ],
III => [ qw( E.P E.Pl P.E.P P.E.Pl Pl.E.P Pl.E.Pl E.P.P E.P.Pl E.Pl.P + E.Pl.Pl ) ],
IV => [ qw( E.E P.E.E Pl.E.E E.P.E E.Pl.E E.E.P E.E.Pl E.E.E ) ]
);
# Hash table/dictionary for all the groups
my #rank = map #$_, #DEF{qw(I II III IV)};
my %rank = map { $rank[$_ - 1] => $_ } 1 .. #rank;
my #group = map { ($_) x #{ $DEF{$_} } } qw(I II III IV);
my %group = map { $rank[$_ - 1] => $group[$_ - 1] . "_" . $_ } 1 .. #group;
sub rank {
$rank{ $a->[2] } <=> $rank{ $b->[2] }
}
my %T;
sub oh {
map values %$_, #_;
}
sub ab {
my ($b, $a) = #_;
[$b->[0], $a->[1], qq($a->[2].$b->[2]), qq($b->[3]<-$a->[3])];
}
sub xtend {
my $a = shift;
map { ab $_, $a } oh #{ $T{ $a->[0] } }{#_};
}
sub ins {
$T{ $_[3] //= $_[1] }{ $_[2] }{ $_[0] } = \#_;
}
ins split /,\s*/ for <DATA>;
#ins split /,\s*/ for $filename;
ins #$_ for map { xtend $_, qw(P E Pl) } (oh oh oh \%T);
ins #$_ for map { xtend $_, qw(P E Pl) } (oh oh oh \%T);
for (sort { rank } grep { $_->[1] eq 'Q' } (oh oh oh \%T)) {
print $out "%-4s: %20s, %-8s %6s\n",
$_->[0],
qq($_->[0]$_->[3]),
$_->[2],
$group{ $_->[2] };
close $in;
close $out;
}
The problem is that it isnt writing anything to the output file.
perl program.pl input_file output_file
Due to certain reasons I want to read in the input file in format, so that cant be done away with.
Please help
input_file
M19,Q,P,
M31,M19,Pl,
M420,M31,E,
M421,M31,E,
M33,M31,E,
M438,M33,Pl,
M445,M33,E,
M437,M33,E,
M444,M33,E,
M73,M33,E,
M552,M73,Pl,
M553,M73,Pl,
M569,M73,E,
M549,M73,E,
M550,M73,E,
The major problems I can see are these
The line open(DATA, $in) is meaningless. I presume you want to test your program with data from the DATA file handle, in which case you want
my $in = \*DATA;
You are closing both file handles inside the final for loop. That means only one line will ever be written to the output, and thereafter you will get the warning
print() on closed filehandle
You are using print with a format. You need printf instead
This variant of your program fixes these things, and produces some output. Is it what you expected?
use strict;
use warnings;
use autodie;
# check that two arguments have been passed
# die "usage: $0 input output\n" unless #ARGV == 2;
my ($infile, $outfile) = #ARGV;
# open my $in_fh, '<', $infile;
# open my $out_fh, '>', $outfile;
my $in_fh = \*DATA;
my $out_fh = \*STDOUT;
my %DEF = (
I => [ qw( P Pl P.P P.Pl Pl.P Pl.Pl P.P.P P.P.Pl P.Pl.P P.Pl.Pl Pl. +P.P Pl.P.Pl Pl.Pl.P Pl.Pl.Pl ) ],
II => [ qw( E P.E Pl.E P.P.E P.Pl.E Pl.P.E Pl.Pl.E ) ],
III => [ qw( E.P E.Pl P.E.P P.E.Pl Pl.E.P Pl.E.Pl E.P.P E.P.Pl E.Pl.P + E.Pl.Pl ) ],
IV => [ qw( E.E P.E.E Pl.E.E E.P.E E.Pl.E E.E.P E.E.Pl E.E.E ) ]
);
# Hash table/dictionary for all the groups
my #rank = map { #$_ } #DEF{qw(I II III IV)};
my %rank = map { $rank[$_ - 1] => $_ } 1 .. #rank;
my #group = map { ($_) x #{ $DEF{$_} } } qw(I II III IV);
my %group = map { $rank[$_ - 1] => $group[$_ - 1] . "_" . $_ } 1 .. #group;
my %T;
sub rank {
$rank{ $a->[2] } <=> $rank{ $b->[2] }
}
sub oh {
map values %$_, #_;
}
sub ab {
my ($b, $a) = #_;
[ $b->[0], $a->[1], qq($a->[2].$b->[2]), qq($b->[3]<-$a->[3]) ];
}
sub xtend {
my $a = shift;
map { ab $_, $a } oh #{ $T{ $a->[0] } }{#_};
}
sub ins {
$T{ $_[3] //= $_[1] }{ $_[2] }{ $_[0] } = \#_;
}
ins split /,\s*/ for <$in_fh>;
close $in_fh;
ins #$_ for map { xtend $_, qw(P E Pl) } (oh oh oh \%T);
ins #$_ for map { xtend $_, qw(P E Pl) } (oh oh oh \%T);
for (sort { rank } grep { $_->[1] eq 'Q' } (oh oh oh \%T)) {
printf $out_fh "%-4s: %20s, %-8s %6s\n",
$_->[0],
qq($_->[0]$_->[3]),
$_->[2],
$group{ $_->[2] };
}
close $out_fh;
__DATA__
M19,Q,P,
M31,M19,Pl,
M420,M31,E,
M421,M31,E,
M33,M31,E,
M438,M33,Pl,
M445,M33,E,
M437,M33,E,
M444,M33,E,
M73,M33,E,
M552,M73,Pl,
M553,M73,Pl,
M569,M73,E,
M549,M73,E,
M550,M73,E,
output
M19 : M19Q, P I_1
M31 : M31M19<-Q, P.Pl I_4
M421: M421M31<-M19<-Q, P.Pl.E II_20
M420: M420M31<-M19<-Q, P.Pl.E II_20
M33 : M33M31<-M19<-Q, P.Pl.E II_20

Parsing CSV with Text::CSV

I am trying to parse a file where the header row is at row 8. From row 9-n is my data. How can I use Text::CSV to do this? I am having trouble, my code is below:
my #cols = #{$csv->getline($io, 8)};
my $row = {};
$csv->bind_columns (\#{$row}{#cols});
while($csv->getline($io, 8)){
my $ip_addr = $row->{'IP'};
}
use Text::CSV;
my $csv = Text::CSV->new( ) or die "Cannot use CSV: ".Text::CSV->error_diag ();
open my $io, "test.csv" or die "test.csv: $!";
my $array_ref = $csv->getline_all($io, 8);
my $record = "";
foreach $record (#$array_ref) {
print "$record->[0] \n";
}
close $io or die "test.csv: $!";
Are you dead-set on using bind_columns? I think I see what you're trying to do, and it's notionally very creative, but if all you want is a way to reference the column by the header name, how about something like this:
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new ( { binary => 1 } );
my (%header);
open my $io, "<", '/var/tmp/foo.csv' or die $!;
while (my $row = $csv->getline ($io)) {
next unless $. > 7;
my #fields = #$row;
unless (%header) {
$header{$fields[$_]} = $_ for 0..$#fields;
next;
}
my $ip_addr = $fields[$header{'IP'}];
print "$. => $ip_addr\n";
}
close $io;
Sample Input:
Test Data,,,
Trash,,,
Test Data,,,
Trash,,,
Beans,Joe,10.224.38.189,XYZ
Beans,Joe,10.224.38.190,XYZ
Beans,Joe,10.224.38.191,XYZ
Last Name,First Name,IP,Computer
Beans,Joe,10.224.38.192,XYZ
Beans,Joe,10.224.38.193,XYZ
Beans,Joe,10.224.38.194,XYZ
Beans,Joe,10.224.38.195,XYZ
Beans,Joe,10.224.38.196,XYZ
Beans,Joe,10.224.38.197,XYZ
Output:
9 => 10.224.38.192
10 => 10.224.38.193
11 => 10.224.38.194
12 => 10.224.38.195
13 => 10.224.38.196
14 => 10.224.38.197

printing hash values in new line using tie

I have a hash with few keys and each key has 20 values.
%test={
a=> 10 14 34 56 ....
b=> 56 67 89 66 ...
..
}
#values= {a,b,..}
I want to tie values from this hash to another file as shown below
my input file.txt
ID
ID
ID
...
expected file.txt
ID ,10 ,56
ID ,14, 67
ID ,34, 89
ID ,56, 66
..
My code right now ties the all the values to the first line of my file. please help formatting it.
my $match = "ID";
tie my #lines, 'Tie::File', 'file.txt' or die "failed : $!";
for my $line (#lines) {
while ( $line =~ /^($match.*)/ ) {
$line = $1 . "," . join ',',#test{#values};
}
}
untie #lines;
right now my output is
file.txt
ID ,10 ,14, 34, 56,... 56, 67, 89, 66....
ID
ID
ID
I'm a bit confused by your question...
You have some template file that only contains ID at the beginning of (n) lines?
And you want to iterate over each $key by $test->{$key}[$line_count]?
Something seems fishy(I think you must be leaving something out) here. There's going to be quite a few ways to go wrong with this design...
Anyways, I think this is what you're going for:
my $match = "ID";
my $test = {
a => [ qw(1 3 5) ],
b => [ qw(2 4 6) ],
};
tie my #lines, 'Tie::File', 'file.txt' or die "failed : $!";
my $i = 0;
for my $line (#lines) {
if( $line =~ /^($match.*)/ ) {
my #stuff = ();
for my $key ( keys %$test ) {
push #stuff, $test->{$key}[$i];
}
$line = $1 . ", " . join(', ', #stuff);
$i++;
}
}
untie #lines;
Assuming that this is what you have/want:
$ cat file.txt
ID
ID
ID
$ test.pl
$ !cat
cat file.txt
ID, 1, 2
ID, 3, 4
ID, 5, 6
Do you simply want
my %test = (
a => [ 10, 14, 34, 56, ... ],
b => [ 56, 67, 89, 66, ... ],
);
for (0..$#{ $test{a} }) {
print(join(',', 'ID', $test{a}[$_], $test{b}[$_]), "\n");
}
You could write to a file instead of STDOUT by creating the file using
open(my $fh, '>', 'file.txt')
or die("Can't create file.txt: $!\n");
and then using
print($fh ...);
but it's better to let the user redirect the output to the file using >file.txt.
Here is my take, although the tie seems superfluous to me:
use strict;
use warnings;
use Tie::File;
my %test=(
a=> [qw(10 14 34 56)],
b=> [qw(56 67 89 66)]
);
my #values= qw(a b);
my $match = "ID";
tie my #lines, 'Tie::File', 'file.txt' or die "failed : $!";
my $i = 0;
for my $line (#lines) {
if ( $line =~ /^($match.*)/ ) {
$line = $1 . "," . join(',', map { $test{$_}->[$i]} #values );
$i++;
}
}
untie #lines;
Output (file.txt):
ID,10,56
ID,14,67
ID,34,89
ID,56,66