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

Hello Monks, my objective is to multiply a column of data in csv file by a factor of say 1.1E3 w/ as little code as possible . I therefore modified the example by Zaxo https://www.perlmonks.org/bare/?node_id=560284 to:

my @multi_array; push @multi_array, [split] for <DATA>; my @by_second = reverse sort {unity} @multi_array; for (@by_second) { print "@{$_}\n"; } sub unity { $b->[1] *= 1.1E3; #sprintf("%E", 0+$b->[1]); return 1;} __DATA__ 1.10000E0 1.00000E0 1.00000E0 2.20000E0 2.00000E0 2.00000E0 3.30000E0 3.00000E0 3.00000E0

This actually works but only sprintf does not. Any advice as to how to keep the scientific notation? Is the usage of "reverse sort" and "$b" a misuse for this purpose?

Replies are listed 'Best First'.
Re: multiplication a column of data in csv file by a factor
by choroba (Cardinal) on Apr 03, 2019 at 13:47 UTC
    Someone said "csv"? A reply using Text::CSV_XS is obligatory!

    use Text::CSV_XS qw{ csv }; csv( in => *DATA, sep_char => ' ', eol => "\n", on_in => sub { $_[1][1] *= 1.1E3; $_[1] = [ map sprintf('%E', $_), @{ $_[1] } ] }, );

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: multiplication a column of data in csv file by a factor
by hippo (Archbishop) on Apr 03, 2019 at 11:37 UTC

    It's not clear to me why you are sorting, reversing etc. A simple while loop will suffice:

    while (my @row = split / /, <DATA>) { $row[1] *= 1.1E3; printf("%E %E %E\n", @row); } exit; __DATA__ 1.10000E0 1.00000E0 1.00000E0 2.20000E0 2.00000E0 2.00000E0 3.30000E0 3.00000E0 3.00000E0
Re: multiplication a column of data in csv file by a factor
by Laurent_R (Canon) on Apr 03, 2019 at 15:44 UTC
    Hi ng0177,

    First please note that the sprintf builtin does not print out anything: it only returns a formatted string. In your code, the call to sprintf does not do anything useful, since you're not using the return value. You need to either use print to print out the string produced by sprintf, or use printf.

    Second, it seems that you're using sort with the aim to modify the values in your array of arrays, rather than for sorting purposes. That's not really the right tool for that. Use a for loop or a map statement (depending on whether you want to modify your data structure in place or create a new data structure).

    Perhaps that's more or less what you looking for:

    use strict; use warnings; my @multi_array = map [split], <DATA>; my @by_second = map {$_->[1] *= 1.1E3; $_;} @multi_array; printf "%E %E %E\n", @{$_}[0..2] for @by_second; __DATA__ 1.10000E0 1.00000E0 1.00000E0 2.20000E0 2.00000E0 2.00000E0 3.30000E0 3.00000E0 3.00000E0
    which produces the following output (which is presumably what you're looking for):
    $ perl split.pl 1.100000E+00 1.100000E+03 1.000000E+00 2.200000E+00 2.200000E+03 2.000000E+00 3.300000E+00 3.300000E+03 3.000000E+00
    If you insist on reducing the number of code lines, you could do it directly (without the auxiliary arrays) like this:
    use strict; use warnings; printf "%E %E %E\n", @{$_}[0..2] for map {$_->[1] *= 1.1E3; $_;} map [ +split], <DATA>;
    or possibly with only one map statement (but the code doesn't get shorter):
    printf "%E %E %E\n", @{$_}[0..2] for map {my $c = [split]; $c->[1] *= +1.1E3; $c;} <DATA>;
    I kept relatively close to your code to try to explain some of the problems in your script and show possible ways to solve them, but, as pointed out by choroba, using Text::CSV might be a good idea.
Re: multiplication a column of data in csv file by a factor
by bliako (Abbot) on Apr 03, 2019 at 11:42 UTC
    my @multi_array; push @multi_array, [split] for <DATA>; $_->[1] *= 1.1E3 for @multi_array; print join("\t", map { sprintf "%E", $_ } @{$_}),"\n" for (@multi_arra +y); __DATA__ 1.10000E0 1.00000E0 1.00000E0 2.20000E0 2.00000E0 2.00000E0 3.30000E0 3.00000E0 3.00000E0

    Unless you want to sort, don't use sort. Unless you want to reverse the order, do not use reverse. Most importantly, sprintf returns a string, it does not print it (like print does).

    bw, bliako

Re: multiplication a column of data in csv file by a factor
by ng0177 (Acolyte) on Apr 03, 2019 at 15:30 UTC
    All very elegant solutions. Thanks for swiftly replying to this common problem!