Hey all,
still a newbie to perl and programming and still needing some advice.. I have a ".CSV" table that I need to do some (rounding) manipulation on. the table looks something like this.. (the real table is actually comma delimited)
DD | H1 | H2 | H3 | H4
---------------------------------------------------
01 | 69.6 | -1 | 55.215 | 25.1231
02 | -1 | 1.23 | 1.45 | -1
I need it to look like this
DD | H1 | H2 | H3 | H4
---------------------------------------------------
01 | 69.9 | -1 | 55.2 | 25.1
02 | -1 | 1.2 | 1.5 | -1
basically I need to round to the tenth ONLY if the value contains more then 1 value after the decimal and i need the values that are "-1" to stay as "-1"
I've read a bunch of tutorials and still just don't get it.. i can get as far as opening the table but not parsing through it... -
#!/usr/bin/perl
-
use strict;
-
use warnings;
-
-
my $fileInput="d:/temp/test.csv";
-
my $fieldnames = 1;
-
-
open (READ, ">>$fileInput") or die "Can't open $fileInput: $!";
-
-
my $header;
-
$header = <READ> if $fieldnames;
-
-
my @data = <READ>;
-
-
print READ $header;
i've also read that this will work for rounding
my($number) = shift;
return int($number + .5)
just not sure how to get to $number
thanks immensely ahead of time!
Cheers,
Eric
running locally on windows XP
8 1824
Greetings Eric,
Now there are a lot of way to do this. Some rather perlish ways would actually take only 1 line of code. However, the following script is an example of how to program this responsibly. It uses two modules that will require installation, but this is how I would do what you proposed: -
use Math::Round::Var;
-
use Text::CSV;
-
use Tie::File;
-
-
use strict;
-
-
my $file = 'test.csv';
-
-
tie my @array, 'Tie::File', $file or die "Can't open $file: $!";
-
-
my $csv = Text::CSV->new();
-
my $rnd = Math::Round::Var->new(0.1);
-
-
for my $i (1..$#array) { # Note, skip 0 index with Header
-
# Parse CSV
-
$csv->parse($array[$i]) or die "parse() failed: ", $csv->error_input;
-
-
# Round number fields.
-
my @fields = $csv->fields;
-
for my $j (0..$#fields) {
-
# Decimal with 2 digit precision
-
if ($fields[$j] =~ m{^-?\d*\.\d{2,}$}) {
-
$fields[$j] = $rnd->round($fields[$j]);
-
}
-
}
-
-
# Resave CSV data
-
$csv->combine(@fields) or die "combine() failed: ", $csv->error_input;
-
$array[$i] = $csv->string;
-
}
-
-
1;
-
-
__END__
-
This takes in the following input file: -
"DD","H1","H2","H3","H4"
-
"01","69.6","-1","55.215","25.1231"
-
"02","-1","1.23","1.45","-1"
-
And changes that file to the following: -
"DD","H1","H2","H3","H4"
-
"01","69.6","-1","55.2","25.1"
-
"02","-1","1.2","1.5","-1"
-
- Miller
Miller,
why not use "sprintf" and "%.1f" ? I realize this will add a .0 (dotzero) to whole numbers but it seems like that would easy to fix if necessary.
Kevin,
You mean actually search perldoc before answering a question. Why would I do that? :) perldoc search "round"
returns: perldoc perlfaq4 Does perl have a round() function?
I simply didn't remember that sprintf had that functionality, because from my viewpoint it should simply truncate. However, actually testing it on data proves that it does in fact round, and amusingly enough that is the implementation method that the Math::Round::Var module uses for decimal rounding. Which probably proves why it's only in version .03 and is likely little used.
That changes my code only slightly, but does clean it up a little. -
use Text::CSV;
-
use Tie::File;
-
-
use strict;
-
-
my $file = 'test.csv';
-
-
tie my @array, 'Tie::File', $file or die "Can't open $file: $!";
-
-
my $csv = Text::CSV->new();
-
-
for my $i (1..$#array) { # Note, skip 0 index with Header
-
# Parse CSV
-
$csv->parse($array[$i]) or die "parse() failed: ", $csv->error_input;
-
-
# Round number fields.
-
my @fields = $csv->fields;
-
for my $j (0..$#fields) {
-
# Decimal with 2 digit precision
-
if ($fields[$j] =~ m{^-?\d*\.\d{2,}$}) {
-
$fields[$j] = sprintf "%.1f", $fields[$j];
-
}
-
}
-
-
# Resave CSV data
-
$csv->combine(@fields) or die "combine() failed: ", $csv->error_input;
-
$array[$i] = $csv->string;
-
}
-
-
1;
-
-
__END__
-
Note, for the "Round number fields" section, I personally would use the following code. But I figure the former is easier to understand for someone new to perl. -
my @fields = map {
-
s{^(-?\d*\.\d{2,})$}{sprintf "%.1f", $1}e; $_
-
} $csv->fields;
-
Thanks for the little reminder Kevin,
- Miller
Thanks again for taking the time to enlighten a newbie! I did just get "programming perl" so hopefully my questions will come less and less and perhaps my replies more and more..
One more thing though.. the input .csv file does not contain 'double quotes' around each data value, but the script output does. The only problem with this is the text files I am processing on are >~200mb as inputs then >~300mb as outputs and we were hoping to reduce the files sizes just a bit by rounding the numbers. Im going to keep searching and hopefully find a solution! but some more insight will always be appreciated!
Cheers,
Eric
There's just no making you happy is there? No matter, your question made me learn something. A better module to use is Text::CSV_XS as it uses a C implementation of the previous module and is therefore much faster. It also has been extended with a lot of additional functionality, including only quoting values that truly require it. They are stylistically the same, so only a renaming of the used module is required.
Final version: -
use Text::CSV_XS;
-
use Tie::File;
-
-
use strict;
-
-
my $file = 'test.csv';
-
-
tie my @array, 'Tie::File', $file or die "Can't open $file: $!";
-
-
my $csv = Text::CSV_XS->new();
-
-
for my $i (1..$#array) { # Note, skip 0 index with Header
-
# Parse CSV
-
$csv->parse($array[$i]) or die "parse() failed: ", $csv->error_input;
-
-
# Round number fields.
-
my @fields = $csv->fields;
-
for my $j (0..$#fields) {
-
# Decimal with 2 digit precision
-
if ($fields[$j] =~ m{^-?\d*\.\d{2,}$}) {
-
$fields[$j] = sprintf "%.1f", $fields[$j];
-
}
-
}
-
-
# Resave CSV data
-
$csv->combine(@fields) or die "combine() failed: ", $csv->error_input;
-
$array[$i] = $csv->string;
-
}
-
-
1;
-
-
__END__
-
You mean actually search perldoc before answering a question. Why would I do that? :)
LOL @ Miller
There's just no making you happy is there?
Im happy now :)
i was reading about the text::csv_xs too but didn't see where it would remove the quotes.... got a long way to go!!
Thanks again Miller and Kevin!
Cheers,
Eric
Sign in to post your reply or Sign up for a free account.
Similar topics
by: spebola |
last post by:
I am using vb.net 2003 professional and I get the following results
when using the round method:
dim Amount as decimal = 180.255
Amount = Amount.Round(Amount, 2)
Amount now contains 180.25. ...
|
by: Zorpiedoman |
last post by:
Howcome:
Dim D as decimal = .5D
msgbox d.Round(D, 0)
this returns "0"
Now when I went to school .5 rounds UP to 1 not DOWN to zero?????!!!
Documentation says this, but what the heck are...
|
by: Jeff Boes |
last post by:
(asked last week on .questions, no response)
Can anyone explain why this happens? (under 7.4.1)
select '2004-05-27 09:00:00.500001-04' :: timestamp(0) ;
timestamp
---------------------...
|
by: Jiri Nemec |
last post by:
Hello all,
I have got one table with rounding values, table contains
prices and round types.
id price_from price_to rounding
1 0 1500 0.1
2 1500 ...
|
by: Marco |
last post by:
Hello,
I have :
float f = 36.09999999;
When I do :
char cf;
sprintf(cf,"%0.03lf", f);
I get : 36.100
|
by: jdrott1 |
last post by:
i'm trying to round my currency string to end in 9. it's for a
pricing application.
this is the function i'm using to get the item in currency:
FormatCurrency(BoxCost, , , , TriState.True)
if...
|
by: Spoon |
last post by:
Hello everyone,
I don't understand how the lrint() function works.
long lrint(double x);
The function returns the nearest long integer to x, consistent with the
current rounding mode. It...
|
by: md |
last post by:
Hi
Does any body know, how to round a double value with a specific number
of digits after the decimal points?
A function like this:
RoundMyDouble (double &value, short numberOfPrecisions)
...
|
by: bdsatish |
last post by:
The built-in function round( ) will always "round up", that is 1.5 is
rounded to 2.0 and 2.5 is rounded to 3.0.
If I want to round to the nearest even, that is
my_round(1.5) = 2 # As...
|
by: =?ISO-8859-1?Q?Marcel_M=FCller?= |
last post by:
clintonb wrote:
There is nothing like an original double amount. If you care about
rounding errors you must not store any currency value in an approximate
number. You must not do this even once....
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome a new...
| |