Re: How to dynamically taking the multiple input arguments?
Edward WIJAYA wrote: Hi John, Hello, I tried your code. But I still cannot remove the whitespace from each line. Suppose I have two files. fileA.txt:fileB.txt: A B A B What I get is: A B A B instead of AB AB I tried to play around with this section of your code but of no avail. # clean up whitespace for ( @data ) { s/^\s+//; s/\s+/ /g; s/ $/\n/; } This should do what you want: #!/usr/bin/perl use warnings; use strict; my ( $line, @data ); while ( ) { s/^\s+//; s/\s+$//; s/\s+/ /g; $data[ $line++ ] .= $_ if /\S/; $line = 0 if eof; } print map $_\n, @data; __END__ John -- use Perl; program fulfillment -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
How to dynamically taking the multiple input arguments?
Hi, I have a simple code that take currently fixed to take 3 input files and append each line of these files together. I wish to know is there anyway I can write the code more flexibly so it can dynamically take the input argument - from minimum 2 files to more. Is there anywhere I can find information about dealing with this matter? Any specific module that cater this problem? Thanks for your time beforehand. Regards, Edward WIJAYA SINGAPORE This is my current (terribly inefficient and unflexible) code: #!/usr/bin/perl -w use strict; use Data::Dumper; if(scalar @ARGV ne 1) { print Usage: $0 file1 file2 [file3] etc\n; exit(1); } #the above part doesn't seem to be working well/useful my $file1 = $ARGV[0]; my @set1 = get_file_data($file1); #Remove the whitspace and \n from each lines @set1 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set1; my $s1 = [EMAIL PROTECTED]; my $file2 = $ARGV[1]; my @set2 = get_file_data($file2); @set2 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set2; my $s2 = [EMAIL PROTECTED]; my $file3 = $ARGV[2]; my @set3 = get_file_data($file3); @set3 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set3; my $s3 = [EMAIL PROTECTED]; #Printout the appended lines from the data print map { join(,$set1[$_],$set2[$_],$set3[$_]), \n } (0..$#set1); #Subroutine sub get_file_data { my ($filename) = @_; use strict; use warnings; # Initialize variables my @filedata = (); unless ( open( GET_FILE_DATA, $filename ) ) { print STDERR Cannot open file \$filename\\n\n; exit; } @filedata = GET_FILE_DATA; close GET_FILE_DATA; return (@filedata); } ___END -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Well, I'm kinda new at this stuff myself, but Here's a couple of things I see right away: On Sat, 11 Sep 2004 10:27:44 +0800, Edward WIJAYA [EMAIL PROTECTED] wrote: Hi, SNIP #!/usr/bin/perl -w --You don't really need to use the -w flag here AND the 'use warnings' in your subroutine down below. use strict; -- Nice Job!! use Data::Dumper; if(scalar @ARGV ne 1) { print Usage: $0 file1 file2 [file3] etc\n; exit(1); } #the above part doesn't seem to be working well/useful --Try this: unless( @ARGV = 2 ) { die Usage: $0 file1 file2 [file3...]\n; } my $file1 = $ARGV[0]; --This is easier and prettier with this: my $file1 = shift; my @set1 = get_file_data($file1); #Remove the whitspace and \n from each lines @set1 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set1; --You can get all the \n's out at once with a chomp: chomp @set1; However, the whole get_file_data thing and chomping can all be done like this: open INFILE, $filename or die Couldn't open $filename: $!\n; chomp( my @filedata = INFILE ); Then, to clear out the whitespace from each line: foreach( @filedata ) { s/\s+//g; } my $s1 = [EMAIL PROTECTED]; my $file2 = $ARGV[1]; my @set2 = get_file_data($file2); @set2 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set2; my $s2 = [EMAIL PROTECTED]; my $file3 = $ARGV[2]; my @set3 = get_file_data($file3); @set3 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set3; my $s3 = [EMAIL PROTECTED]; #Printout the appended lines from the data print map { join(,$set1[$_],$set2[$_],$set3[$_]), \n } (0..$#set1); #Subroutine sub get_file_data { my ($filename) = @_; use strict; use warnings; # Initialize variables my @filedata = (); unless ( open( GET_FILE_DATA, $filename ) ) { print STDERR Cannot open file \$filename\\n\n; exit; } @filedata = GET_FILE_DATA; close GET_FILE_DATA; return (@filedata); } SNIP Not much, I know, but I'm sure some of the others on the list will help out more. I'll work on this some more and post what I figure out later. --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Here ya go ... this works for me. I tested it with up to 5 input files and it was still workin'. It does have a bug, though. It doesn't check whether all the input files are the same length. Nor did I test what happens when they AREN'T the same length. Let me know what ya think: #!/usr/bin/perl use warnings; use strict; unless( @ARGV = 2 ) { die Usage: $0 file1 file2 [file3...]\n; } my @results; foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } foreach( @results ) { print $_\n; } --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } This is a little shorter and saves on iterations: for my $file (@ARGV) { open IN, $file or die Couldn't open $file: $!\n; @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (IN); close IN; } -David On Fri, 10 Sep 2004 11:35:09 -0500, Errin Larsen [EMAIL PROTECTED] wrote: Here ya go ... this works for me. I tested it with up to 5 input files and it was still workin'. It does have a bug, though. It doesn't check whether all the input files are the same length. Nor did I test what happens when they AREN'T the same length. Let me know what ya think: #!/usr/bin/perl use warnings; use strict; unless( @ARGV = 2 ) { die Usage: $0 file1 file2 [file3...]\n; } my @results; foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } foreach( @results ) { print $_\n; } --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
On Fri, 10 Sep 2004 12:44:51 -0400, David Greenberg [EMAIL PROTECTED] wrote: foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } This is a little shorter and saves on iterations: for my $file (@ARGV) { open IN, $file or die Couldn't open $file: $!\n; @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (IN); close IN; } -David Can you throw the 'chomp' in the assignment in that 'map' statement? Then, can you also throw in the substitution in the mix? like this: @results = map{ my $line = chomp( s/\s+//g ); } ( IN ); And if so, why not this: @results = map{ chomp( s/\s+//g ) } ( IN ); As long as we're playing Perl-Golf!! I truly don't understand what 'map' is doing. Can you explain it to me? I have tried to read perldoc -f map but it's a little weird and hard to follow! --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
I'm no expert, but chomp won't give you what you think it will: my @arr = ('a', b\n, c\n); print join (,,chomp (@arr)); This will print: 2 while this: my @arr = ('a', b\n, c\n); chomp (@arr); print join (,,@arr); will print: a,b,c Map will run whatever is in the code block (between the {}'s) on every value in the list passed to it (between the ()'s). The last statement in the code block is like a return value. Map builds the results list out of all of the return values. With a foreach loop, it would be: my @results = (); foreach (IN) { my $line = $_; chomp $line; $line =~ s/\s+//g; push (@results, $line); #appends $line to the @results list } Hope this helps. -David On Fri, 10 Sep 2004 11:58:30 -0500, Errin Larsen [EMAIL PROTECTED] wrote: On Fri, 10 Sep 2004 12:44:51 -0400, David Greenberg [EMAIL PROTECTED] wrote: foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } This is a little shorter and saves on iterations: for my $file (@ARGV) { open IN, $file or die Couldn't open $file: $!\n; @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (IN); close IN; } -David Can you throw the 'chomp' in the assignment in that 'map' statement? Then, can you also throw in the substitution in the mix? like this: @results = map{ my $line = chomp( s/\s+//g ); } ( IN ); And if so, why not this: @results = map{ chomp( s/\s+//g ) } ( IN ); As long as we're playing Perl-Golf!! I truly don't understand what 'map' is doing. Can you explain it to me? I have tried to read perldoc -f map but it's a little weird and hard to follow! --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } This is a little shorter and saves on iterations: for my $file (@ARGV) { open IN, $file or die Couldn't open $file: $!\n; @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; @results seems would be re-assigned when the next file comes... Besides, I guess chomp is not nesessary here.. \s+ means [\t\r\n\f]+, so \r, \n or \r\n would seem to be cleared by the s expression. $line } (IN); close IN; } I would suggest to write in this way : my @res = (); foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; my @data = IN; close IN; s/\s+//g for @data; @res = ( @res, @data ); } Code not been tested, but the concept is something like this. HTH -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
On Fri, 10 Sep 2004 13:17:40 -0400, David Greenberg [EMAIL PROTECTED] wrote: I'm no expert, but chomp won't give you what you think it will: my @arr = ('a', b\n, c\n); print join (,,chomp (@arr)); This will print: 2 while this: my @arr = ('a', b\n, c\n); chomp (@arr); print join (,,@arr); will print: a,b,c Map will run whatever is in the code block (between the {}'s) on every value in the list passed to it (between the ()'s). The last statement in the code block is like a return value. Map builds the results list out of all of the return values. With a foreach loop, it would be: my @results = (); foreach (IN) { my $line = $_; chomp $line; $line =~ s/\s+//g; push (@results, $line); #appends $line to the @results list } Hope this helps. -David Thanks, David, for the 'map' explanation. However, I've been playing with this code, and, after your suggestion (above) it seems to be broken. Originally, the question was, taking atleast 2 seperate text files on the command line, smoosh them together like this: # ./smoosher file1 file2 OneFirst TwoSecond ThreeThird if our text files are: file1: One Two Three file2: First Second Third The code I have so far is (after your suggestion): smoosher: #!/usr/bin/perl use warnings; use strict; unless( @ARGV = 2 ) { die Usage: $0 file1 file2 [file3...]\n; } my @results = (); foreach my $file ( @ARGV ) { open IN, $file or die Couldn't open $file: $!\n; @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (IN); close IN; } foreach( @results ) { print $_\n; } The first 'foreach' block in my original code, which was working, was: foreach my $file ( @ARGV ) { open IN, $file or die Couldn't open $file: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } So my question is, how can we use the map function, as you suggest, to reduce the number of iterations, yet still keep our desired output? The key was the $results[$_] .= $data[$_]; line in there, which appended the current files line to the results array, as opposed to replacing it, which is what our new code seems to do. --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
On Sat, 11 Sep 2004 02:20:32 +0800, Bee [EMAIL PROTECTED] wrote: foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } This is a little shorter and saves on iterations: for my $file (@ARGV) { open IN, $file or die Couldn't open $file: $!\n; @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; @results seems would be re-assigned when the next file comes... Besides, I guess chomp is not nesessary here.. \s+ means [\t\r\n\f]+, so \r, \n or \r\n would seem to be cleared by the s expression. $line } (IN); close IN; } I would suggest to write in this way : my @res = (); foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; my @data = IN; close IN; s/\s+//g for @data; @res = ( @res, @data ); } Code not been tested, but the concept is something like this. HTH Ok ... Thanks for helpin' out, HTH! I tried out your suggestions and now the code looks like this: #!/usr/bin/perl use warnings; use strict; unless( @ARGV = 2 ) { die Usage: $0 file1 file2 [file3...]\n; } my @results = (); foreach my $file ( @ARGV ) { open IN, $file or die Couldn't open $file: $!\n; my @data = IN; close IN; s/\s+//g foreach( @data ); @results = ( @results, @data ); } foreach( @results ) { print $_\n; } But now the output is as follows. We want the output to look like this: OneFirst TwoSecond ThreeThird But instead, it's coming out like this: One Two Three First Second Third Given the two test input files: file1: file2: OneFirst TwoSecond Three Third --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Opps, I missed that. Instead of: @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (@data); try: my @newresults = map { my $line = $_; chomp $line; $line =~ s/\s+//g; shift (@results) . $line } (@data); @results = @newresults; -David On Fri, 10 Sep 2004 13:40:04 -0500, Errin Larsen [EMAIL PROTECTED] wrote: On Sat, 11 Sep 2004 02:20:32 +0800, Bee [EMAIL PROTECTED] wrote: foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } This is a little shorter and saves on iterations: for my $file (@ARGV) { open IN, $file or die Couldn't open $file: $!\n; @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; @results seems would be re-assigned when the next file comes... Besides, I guess chomp is not nesessary here.. \s+ means [\t\r\n\f]+, so \r, \n or \r\n would seem to be cleared by the s expression. $line } (IN); close IN; } I would suggest to write in this way : my @res = (); foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; my @data = IN; close IN; s/\s+//g for @data; @res = ( @res, @data ); } Code not been tested, but the concept is something like this. HTH Ok ... Thanks for helpin' out, HTH! I tried out your suggestions and now the code looks like this: #!/usr/bin/perl use warnings; use strict; unless( @ARGV = 2 ) { die Usage: $0 file1 file2 [file3...]\n; } my @results = (); foreach my $file ( @ARGV ) { open IN, $file or die Couldn't open $file: $!\n; my @data = IN; close IN; s/\s+//g foreach( @data ); @results = ( @results, @data ); } foreach( @results ) { print $_\n; } But now the output is as follows. We want the output to look like this: OneFirst TwoSecond ThreeThird But instead, it's coming out like this: One Two Three First Second Third Given the two test input files: file1: file2: OneFirst TwoSecond Three Third --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
On Fri, 10 Sep 2004 15:01:34 -0400, David Greenberg [EMAIL PROTECTED] wrote: Opps, I missed that. Instead of: @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (@data); try: my @newresults = map { my $line = $_; chomp $line; $line =~ s/\s+//g; shift (@results) . $line } (@data); @results = @newresults; -David Ok ... please forgive my n00b-ness, but can you help me understand a couple of things here. This part: shift (@results) . $line Is it the same as: shift @results . $line I'm thinking no. But I don't know what the difference is. I also don't understand what exactly that shift is doing, but if I understand the difference with the parens maybe It'll start to make more sense to me. --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Ok ... Thanks for helpin' out, HTH! I tried out your suggestions and now the code looks like this: You are welcome, but my name is Bee, HTH stands for 'Hope This Help' #!/usr/bin/perl use warnings; use strict; unless( @ARGV = 2 ) { die Usage: $0 file1 file2 [file3...]\n; } my @results = (); foreach my $file ( @ARGV ) { open IN, $file or die Couldn't open $file: $!\n; my @data = IN; close IN; s/\s+//g foreach( @data ); @results = ( @results, @data ); Oops... sorry for I've confused for what you expected, so instead the above line with this : $results[$_] .= $data[$_] for (0..$#data) ; # would almostly do what you want now ! -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
I'm not sure if shift (@results) . $line; and shift @results . $line would work differently. It depends on whether the order of operations gives precedence to . or to handing an argument to a function. My guess is that . gets precedence, in which case shift @results . $line; will give you something weird that you don't want. I suggest you look up the perldocs on shift, but basically if you have any array, like: my @arr = ('a', 'b', 'c'); the result of: print shift (@arr); will be: a and @arr will now only be: ('b', 'c') In other words, it takes the first element off of the array. It is often used to get arguments to a function: sub foo { my $arg1 = shift; my $arg2 = shift; print $arg1 . . $arg2; } foo (hello, world); would print: hello world So, shift (@results) . $line; is taking the next value from @results and appending $line to it. That value will then be the next value in @newresults. It takes a bit of getting used to. I suggest reading a little about functional programming to fully grasp the list manipulation functions like map, grep, split, join, etc. -David On Fri, 10 Sep 2004 14:37:28 -0500, Errin Larsen [EMAIL PROTECTED] wrote: On Fri, 10 Sep 2004 15:01:34 -0400, David Greenberg [EMAIL PROTECTED] wrote: Opps, I missed that. Instead of: @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (@data); try: my @newresults = map { my $line = $_; chomp $line; $line =~ s/\s+//g; shift (@results) . $line } (@data); @results = @newresults; -David Ok ... please forgive my n00b-ness, but can you help me understand a couple of things here. This part: shift (@results) . $line Is it the same as: shift @results . $line I'm thinking no. But I don't know what the difference is. I also don't understand what exactly that shift is doing, but if I understand the difference with the parens maybe It'll start to make more sense to me. --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Opps, I missed that. Instead of: @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (@data); try: my @newresults = map { my $line = $_; chomp $line; $line =~ s/\s+//g; shift (@results) . $line } (@data); @results = @newresults; -David This works fine, but can be simplier : my @newresults = map { s/\s+//g; shift (@results) . $_ } (@data); Ok ... please forgive my n00b-ness, but can you help me understand a couple of things here. This part: shift (@results) . $line This means : $x = shift @result; # where $x means to $_ or the value carries in memory. $x = $x . $line Is it the same as: shift @results . $line While this means : $x = @results . $line ; # @results here means scalar @results ( how many elems inside @results ) shift $x ; # then cause error. I'm thinking no. But I don't know what the difference is. I also The difference is the scope for the 'shift' , with ( ), the scope for shift is @results, without ( ) , the scope for shift is @results . $line . don't understand what exactly that shift is doing, but if I understand perldoc -f shift -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Fwd: How to dynamically taking the multiple input arguments?
I forgot to CC the list with my last post! sorry, won't happen again. --Errin -- Forwarded message -- From: Errin Larsen [EMAIL PROTECTED] Date: Fri, 10 Sep 2004 15:46:33 -0500 Subject: Re: How to dynamically taking the multiple input arguments? To: Bee [EMAIL PROTECTED] Alrighty ... So the code I've got now is below. Some of the variables' names have changed to make things slightly less confusing (probably only less confusing for me!). I also moved those parens arount the 'shift' function so it communicates the precendence (again, in my opinion) a little more clearly. I have tested this and it seems to work! comments? #!/usr/bin/perl use warnings; use strict; unless( @ARGV = 2 ) { die Usage: $0 file1 file2 [file3...]\n; } my @final_results = (); foreach my $file ( @ARGV ) { open IN, $file or die Couldn't open $file: $!\n; my @tmp_results = map{ s/\s+//g; ( shift @final_results ).$_ } ( IN ); @final_results = @tmp_results; close IN; } print $_\n foreach( @final_results ); btw, thanks for all the help and explanations David and Bee (sorry about my ignorance of the HTH!). I hope Edward (the original poster!) has been paying attention! --Errin -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Edward WIJAYA wrote: Hi, Hello, I have a simple code that take currently fixed to take 3 input files and append each line of these files together. I wish to know is there anyway I can write the code more flexibly so it can dynamically take the input argument - from minimum 2 files to more. Is there anywhere I can find information about dealing with this matter? Any specific module that cater this problem? You could use the paste program to do that. man paste This is my current (terribly inefficient and unflexible) code: #!/usr/bin/perl -w use strict; use Data::Dumper; if(scalar @ARGV ne 1) You are using 'ne' which compares strings when you should be using '!=' which is used to compare numbers. Both the comparison operator and the if conditional force scalar context so using 'scalar' is redundant. if ( @ARGV != 1 ) However that only works if the command line has exactly one filename and you want to require two or more. if ( @ARGV = 2 ) { print Usage: $0 file1 file2 [file3] etc\n; exit(1); } #the above part doesn't seem to be working well/useful my $file1 = $ARGV[0]; my @set1 = get_file_data($file1); perldoc -q quoting Found in /usr/lib/perl5/5.8.2/pod/perlfaq4.pod What's wrong with always quoting $vars? #Remove the whitspace and \n from each lines @set1 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set1; my $s1 = [EMAIL PROTECTED]; my $file2 = $ARGV[1]; my @set2 = get_file_data($file2); @set2 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set2; my $s2 = [EMAIL PROTECTED]; my $file3 = $ARGV[2]; my @set3 = get_file_data($file3); @set3 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set3; my $s3 = [EMAIL PROTECTED]; #Printout the appended lines from the data print map { join(,$set1[$_],$set2[$_],$set3[$_]), \n } (0..$#set1); #Subroutine sub get_file_data { my ($filename) = @_; use strict; use warnings; use() keeps track of which modules have been loaded so use()ing the same module more than once will not incur more overhead and will not do anything useful either. # Initialize variables my @filedata = (); my() creates a lexical variable in an undefined state so assigning an undefined value to it is redundant. unless ( open( GET_FILE_DATA, $filename ) ) { print STDERR Cannot open file \$filename\\n\n; You should include the $! (or $^E) variable in the error message so you know why open() failed. exit; } @filedata = GET_FILE_DATA; close GET_FILE_DATA; return (@filedata); If you had used a lexical filehandle you could have skipped the assignment to an array. } ___END A valid __END__ token has two underscore characters before and after 'END'. You have two basic options for merging files, store all the contents in memory which may run out of memory, or read each file line by line which may run out of file handles. If the aggregate data will fit in memory you can do this: #!/usr/bin/perl use warnings; use strict; my ( $line, @data ); while ( ) { $data[ $line++ ] .= $_ if /\S/; $line = 0 if eof; } # clean up whitespace for ( @data ) { s/^\s+//; s/\s+/ /g; s/ $/\n/; } print @data; __END__ And if you need to read each file a line at a time you could do something like this: #!/usr/bin/perl use warnings; use strict; my @fhs = map { open my $fh, '', $_ or die $_: $!; $fh } @ARGV; while ( @fhs ) { my $line = ''; for ( @fhs ) { defined( my $curr = $_ ) or next; redo unless $curr =~ /\S/; $line .= $curr; } for ( $line ) { s/^\s+//; s/\s+/ /g; s/ $/\n/; } print $line; @fhs = grep !eof( $_ ), @fhs; } __END__ John -- use Perl; program fulfillment -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Errin Larsen wrote: On Fri, 10 Sep 2004 12:44:51 -0400, David Greenberg [EMAIL PROTECTED] wrote: foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; chomp( my @data = IN ); close IN; foreach( @data ) { s/\s+//g; } foreach( 0..$#data ) { $results[$_] .= $data[$_]; } } This is a little shorter and saves on iterations: for my $file (@ARGV) { open IN, $file or die Couldn't open $file: $!\n; @results = map { my $line = $_; chomp $line; $line =~ s/\s+//g; $line } (IN); close IN; } Can you throw the 'chomp' in the assignment in that 'map' statement? No. Then, can you also throw in the substitution in the mix? No. like this: @results = map{ my $line = chomp( s/\s+//g ); } ( IN ); The substitution operator returns the number of substitutions performed or false if there were no substitutions. chomp() returns the number of chomps performed. map returns the value of the last statement in the code block. So, assuming s/\s+//g returns a number and $/ hasn't been changed, chomp will assign 0 to $line which map will return for every line from IN. And if so, why not this: @results = map{ chomp( s/\s+//g ) } ( IN ); Again, map will return 0 for every line from IN. Also, the parentheses around the readline operator are redundant as map forces list context. As long as we're playing Perl-Golf!! I truly don't understand what 'map' is doing. Can you explain it to me? I have tried to read perldoc -f map but it's a little weird and hard to follow! map takes a list, modifies each element, and returns the modified list. John -- use Perl; program fulfillment -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Bee wrote: I would suggest to write in this way : my @res = (); foreach( @ARGV ) { open IN, $_ or die Couldn't open $_: $!\n; my @data = IN; close IN; s/\s+//g for @data; @res = ( @res, @data ); You are copying the @res array. It would be more efficient using push. push @res, @data; John -- use Perl; program fulfillment -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Errin Larsen wrote: Ok ... please forgive my n00b-ness, but can you help me understand a couple of things here. This part: shift (@results) . $line Is it the same as: shift @results . $line I'm thinking no. But I don't know what the difference is. I also don't understand what exactly that shift is doing, but if I understand the difference with the parens maybe It'll start to make more sense to me. If you had actually tried to run them you would have seen that the second one does not even compile. :-) John -- use Perl; program fulfillment -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response
Re: How to dynamically taking the multiple input arguments?
Hi John, I tried your code. But I still cannot remove the whitespace from each line. Suppose I have two files. fileA.txt:fileB.txt: A B A B What I get is: A B A B instead of AB AB I tried to play around with this section of your code but of no avail. # clean up whitespace for ( @data ) { s/^\s+//; s/\s+/ /g; s/ $/\n/; } Hope to heare from you again. Regards Edward WIJAYA -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/ http://learn.perl.org/first-response