user1976336
user1976336

Reputation: 217

Perl/Ruby one-liner array manipulation

Hello I am trying to make a one-liner in perl( or ruby ) that reads data from a file into an array, and prints it in columns with a newline after ever 10nth element.

The file is like this

Name
Course1
Mark1
Course2
Mark2
Course3
Mark3
Course4
Mark4

And should be displayed like this

Name   Course1  Mark1   Course2   Mark2   Course3   Mark3   Course4   Mark4

This is what I have tried to far

perl -ne '@a=split"\n",$_;print join("\t"=>splice@a,0,10)' Data.txt 

Upvotes: 0

Views: 283

Answers (4)

the Tin Man
the Tin Man

Reputation: 160551

The data sample is only nine lines, so it won't fit conveniently into a ten-line bucket. I added a placeholder so my text file looks like:

Name
Course1
Mark1
Course2
Mark2
Course3
Mark3
Course4
Mark4
-----
Name
Course1
Mark1
Course2
Mark2
Course3
Mark3
Course4
Mark4
-----

I'd do it in Ruby something along these lines:

puts ARGF.lines.map(&:chomp).each_slice(10).map{ |a| a.join(' ') }

Which gives me an output like:

Name Course1 Mark1 Course2 Mark2 Course3 Mark3 Course4 Mark4 -----
Name Course1 Mark1 Course2 Mark2 Course3 Mark3 Course4 Mark4 -----

Using tabs instead of spaces is trivial: replace ' ' with "\t", but how is left as an exercise for the reader.

map(&:chomp) strips the trailing line-endings so the fields can exist on one line when printed. each_slice(10) grabs array elements ten at a time, which results in an array-of-arrays, each sub-array containing ten strings. The final map{ |a| a.join(' ') } joins the sub-arrays with spaces, or tabs if changed to "\t". Alternately, a * ' ' or a * "\t" could have been used instead of join, but join is more commonly used.

Upvotes: 0

ikegami
ikegami

Reputation: 385996

That doesn't work because you're splitting on newlines when you read a line at a time. You'd need -0777 to make it work.

You also only print the first 10 elements, so you'd need to introduce a loop.

perl -0777nE'@F = split /\n/; say join "\t", splice @F,0,10 while @F' Data.txt 

That begs to take advantage of -a!

perl -F'\n' -0777naE'say join "\t", splice @F,0,10 while @F' Data.txt 

Or we can take a completely different approach. Short and sweet:

perl -pe's/\n/\t/ if $. % 10' Data.txt

If there isn't a multiple of 10 columns, that will end with a trailing tab instead of a newline. Ok, not so good. Then how about

perl -0777pe's/\n(?!\z)/ ++$i % 10 ? "\t" : "\n" /eg' Data.txt

Update You've since changed your question to request fixed-width fields.

If you know the width in advance (say 10 + 2 chars between fields = 12):

perl -F'\n' -0777naE'say pack "(A12)9 A*", splice @F,0,10 while @F' Data.txt 

If you don't:

perl -MList::Util=max -F'\n' -0777naE'
   $w = 2 + max map length, @F;
   say pack "(A$w)9 A*", splice @F,0,10 while @F;
' Data.txt 

Upvotes: 5

also
also

Reputation: 974

ruby -e 'ARGF.map{|l|l.strip}.each_slice(10) {|a| puts a.join "\t"}' Data.txt

Upvotes: 2

chrsblck
chrsblck

Reputation: 4088

ikegami beat me to it. But I'll post mine anyways.

perl -pe 'tr/\n/\t/ if $. % 9 != 0'

EDIT: Ah, even better. Thanks ikegami( for the $., I forgot about that one).

Upvotes: 0

Related Questions