views:

107

answers:

4

Say I have a data file that I want to process; I want to take the maximum value of each of the column and append it to the end of each line.

INPUT:

T1 T2 T3
35.82 34.67 31.68
32.20 34.52 33.59
37.41 38.64 37.56

OUTPUT:

T1 T2 T3
35.82 34.67 31.68 35.82
32.20 34.52 33.59 34.52
37.41 38.64 37.56 38.64

I'm trying to implement this as a one-liner. So far, this is what I've come up with, although it complains that &main::max is undefined:

perl -MList::Util -ani.bak -e "print qq(@F).q( ).max(@F).qq(\n)" file1.txt

It seems that I haven't loaded the List::Util module. What's wrong? And is the header column an issue?

perlrun doesn't have a decent example on how to do this (actually it does, my documentation was a little hard to read).

+12  A: 

You loaded List::Util, but the module doesn't export symbols by default. Skip the header line by checking whether $. is 1.

$ perl -MList::Util=max -ape 's/$/" " . max(@F)/e unless $.==1' input 
T1 T2 T3
35.82 34.67 31.68 35.82
32.20 34.52 33.59 34.52
37.41 38.64 37.56 38.64

The perlrun documentation explains:

A little builtin syntactic sugar means you can also say -mmodule=foo,bar or -Mmodule=foo,bar as a shortcut for -Mmodule qw(foo bar). This avoids the need to use quotes when importing symbols. The actual code generated by -Mmodule=foo,bar is use module split(/,/,q{foo,bar}). Note that the = form removes the distinction between -m and -M.

Greg Bacon
Sweet. The `s///e` trick is a nice little takeaway. Just need to make sure it works for inline editing.
Zaid
It does. I modified it to include a new header as well: `perl -i.bak -MList::Util=max -ape 's/$/" " .($.===1 ? "TMAX" : max(@F))/e' input`
Zaid
+3  A: 
perl -M"List::Util 'max'" -ani.bak -e "print qq(@F).q( ).max(@F).qq(\n)" file1.txt
draegtun
+1  A: 

List::Util was loaded, but it doesn't export the max function by default:

perl -MList::Util -ani.bak -e "print qq(@F).q( ).List::Util::max(@F).qq(\n)" file1.txt
Dave Sherohman
Eh? Any clue on why the downvote?
Dave Sherohman
+1  A: 

if Perl is not a must, here's an awk one-liner

$ awk '{for(i=1;i<=NF;i++)if($i>t){t=$i};print $0,t;t=0}' file
35.82 34.67 31.68 35.82
32.20 34.52 33.59 34.52
37.41 38.64 37.56 38.64
ghostdog74