Re: Multiply the numbers in a text file
by pvaldes (Chaplain) on May 09, 2015 at 21:52 UTC
|
Divide your problem in smaller chunks
1-You will need to acces to the input file values, so study how to create a filehandle with the function open. Open a terminal and write perldoc PerlIO for the man pages.
2-You'll need to select your desired numbers. How to do this depend on what is your strategy to pick a number and discard another but you will need probably a regexp. See perldoc perlrequick for a short intro and perldoc perlre for a more extensive and complete manual
3-Replace all non-zero values. See "search and replace" in perldoc perlrequick. Register your values to a variable and then multiply your var with something like '$mynevvalue = $myoldvalue * 5'
4-print out the text file: you'll need an output filehandle. Read 'perldoc PerlIO' and study the function open.
5-don't forget to close both filehandles with the function close
| [reply] |
Re: Multiply the numbers in a text file
by edimusrex (Monk) on May 09, 2015 at 21:57 UTC
|
What does the file look like with the numbers? Is it in a list type format? If so you could load the file into an array and assign the array elements to a variable.
Lets say your number file looks like this
123
12
52
15
27
336
Load the file into an array like so
open FILE, "<", "file.txt";
chomp(@array=<FILE>);
close FILE;
This will give you an array which would have the all the values loaded from the file. If you wanted to multiply them by a constant I would loop through the array and do a conditional check on each element. Here is an example script which will write out to a new file
#!/usr/bin/perl
my $input = 'input.txt';
my $output = 'output.txt';
my $constant = 15; #number you are multiplying by
open FILE, "<", $input;
chomp(my @array=<FILE>);
close FILE;
for(@array) {
if ($_ > 20) {
open OUTPUT, ">>", $output;
print OUTPUT ($_ * $constant)."\n";
close OUTPUT;
}
}
| [reply] [d/l] [select] |
|
Adding best practices (Local filehandles, error checking), and efficiency to your code, and adding a zero value check as the OP requested:
#!/usr/bin/perl
use strict;
use warnings;
my $input = 'input.txt';
my $output = 'output.txt';
my $constant = 15; #number you are multiplying by
my $minimum = 20; # Smallest number to multiply
my $zero_replace = 666; # Replacement for zero
open my $in, "<", $input or die "Could not open $input for reading:$!"
+;
open my $out, ">>", $output or die "Could not open $output for append:
+$!";
while (<$in>){
chomp $_;
$_ = $zero_replace if 0 == $_; #
next if $_ < $minimum;
print $out ($_ * $constant),"\n";
}
close $in;
close $out;
"You're only given one little spark of madness. You mustn't lose it." - Robin Williams
| [reply] [d/l] |
|
| [reply] [d/l] |
|
|
Hello edimusrex,
Although loading the file into an array can be done and will work with your data sample, it might encounter memory shortage problem if the input data is very large and it is not very efficient. With a problem such as the one in the original post, it is simpler, more efficient and much safer to read the input file line by line and process each line in turn.
Also the syntax you are proposing (bare word file handles) has been outdated for more than ten years. Look at NetWallah's reply to your post, the syntax in this reply is much more in accordance with the best practices commonly endorsed by the Perl Community these days. Also never open a file without checking if the opening succeeded (or failed).
I almost considered down voting your post for a few seconds, but I did not because the code seems to be correct (I mean workable), and also because you were obviously trying to be helpful. But you should try to use more modern Perl syntax.
| [reply] |
|
Thanks for the tip. What I've learned in Perl has been taught and learned from some seasoned programmers so it would make sense that I am using "outdated" syntax. I'll take a look at newer standards. I do however always use error checking in production code, just didn't throw it in in my example.
| [reply] |
|
ncols 498
nrows 541
xllcorner 1394682.720294049475
yllcorner 1751328.700356452260
cellsize 2000.000000000000
NODATA_value -9999
-9999 -9999 -9999 -9999 -9999 -9999 0.09 -0.001
Though it is a lot bigger in terms of the number of rows and columns.
So what i want to do is skip the first six lines and multiply the rest of the text excluding -9999 with a constant. Also all the small negative values should be converted to 0 or -9999. The resulting can be overwritten onto the same text file or onto a new file. Thanks a lot for your help
| [reply] [d/l] |
|
Now that you've provided some sample data, we can accomplish something. You still need to make your requirements more concrete, though. What qualifies as a "small negative value"? All negative values, or ones below a certain value? If these should be converted to "0 or -9999", which should it choose? If some should be 0 and some should be -9999, based on what criteria? If you hired me to write this script, I would need you to answer those questions.
To get you started, you can skip the first six lines by simply reading and writing them:
for (1..6){
$line = <$input_file>;
print $output_file $line;
}
Then proceed with your filtering on the remaining lines. I'll guess that you want all negative values smaller than -0.1 replaced with 0 or -9999 alternatively, assume that values are space-delimited, and continue:
my $M = 5; # constant multiplier
my $T = 0.1 # negative number threshold
my $al = 0; # alternator
while(<$input_file>){
s|([-.\d]+)|
if($1 == -9999){
$1; # leave -9999 alone
} elsif( $1 < 0 and abs($1) < $T ){
$al++ % 2 ? 0 : -9999; # replace small negative with 0 or -999
+9
} else {
$1 * $M; # multiply other numbers by constant
}
|ge;
print $output_file;
}
If you want your changes to replace the original file, the best way to do that is to write to a new file and then copy it over the old file when you're finished. You can do that copy manually, or make that part of your script after you've tested enough to be confident that it will work correctly.
Aaron B.
Available for small or large Perl jobs and *nix system administration; see my home node.
| [reply] [d/l] [select] |
|
|
|