views:

334

answers:

12

I have some data on a single line like below

abc edf xyz rfg yeg udh

I want to present the data as below

abc
xyz
yeg


edf
rfg
udh

so that alternate fields are printed with newline separated. Are there any one liners for this?

+6  A: 

The following awk script can do it:

> echo 'abc edf xyz rfg yeg udh' | awk '{
    for (i = 1;i<=NF;i+=2){print $i}
    print "";
    for (i = 2;i<=NF;i+=2){print $i}
    }'
abc
xyz
yeg

edf
rfg
udh
paxdiablo
Please see my question completely "alternate fields are printed with newline separated"
Vijay Sarathi
Impatient little thing, aren't you? :-) I assume you'll be reversing that downvote now that the answer is correct.
paxdiablo
Thanks for that :-) Cheers.
paxdiablo
Cool...this is really nice .thanks Pax
Vijay Sarathi
+4  A: 

Python in the same spirit as the above awk (4 lines):

$ echo 'abc edf xyz rfg yeg udh' | python -c 'f=raw_input().split()
> for x in f[::2]: print x
> print
> for x in f[1::2]: print x'

Python 1-liner (omitting the pipe to it which is identical):

$ python -c 'f=raw_input().split(); print "\n".join(f[::2] + [""] + f[1::2])'
Alex Martelli
The "another answer has been posted" didn't come up. Glad to know I'm not the only one who had this idea. Python has nicer array slicing syntax. This is (IMHO) one of the most annoying omissions from Perl (that and string indexing).
Chris Lutz
+2  A: 

Just for comparison, here's a few Perl scripts to do it (TMTOWTDI, after all). A rather functional style:

#!/usr/bin/perl -p

use strict;
use warnings;

my @a = split;
my @i = map { $_ * 2 } 0 .. $#a / 2;
print join("\n", @a[@i]), "\n\n",
      join("\n", @a[map { $_ + 1 } @i]), "\n";

We could also do it closer to the AWK script:

#!/usr/bin/perl -p

use strict;
use warnings;

my @a = split;
my @i = map { $_ * 2 } 0 .. $#a / 2;
print "$a[$_]\n" for @i;
print "\n";
print "$a[$_+1]\n" for @i;

I've run out of ways to do it, so if any other clever Perlers come up with another method, feel free to add it.

Chris Lutz
A: 

you could also just use tr: echo "abc edf xyz rfg yeg udh" | tr ' ' '\n'

Dotti
This won't work. The OP wants to have the fields rearranged.
Chris Lutz
This just replaces spaces with newlines; printing the fields in order on separate lines -- which is not what the poster is looking for.
Ian Clelland
+1  A: 

Another Perl solution:

use strict;
use warnings;

while (<>)
{
    my @a = split;
    my @b = map { $a[2 * ($_%(@a/2)) + int($_ / (@a /2))]  . "\n" } (0 .. @a-1); 
    print join("\n", @a[0..((@b/2)-1)], '', @a[(@b/2)..@b-1], '');
}

You could even condense it into a real one-liner:

perl -nwle'my @a = split;my @b = map { $a[2 * ($_%(@a/2)) + int($_ / (@a /2))]  . "\n" } (0 .. @a-1);print join("\n", @a[0..((@b/2)-1)], "", @a[(@b/2)..@b-1], "");'
Ether
Too much golf, not enough work!
Chris Lutz
A: 

Here's the too-literal, non-scalable, ultra-short awk version:

awk '{printf "%s\n%s\n%s\n\n%s\n%s\n%s\n",$1,$3,$5,$2,$4,$6}'

Slightly longer (two more characters), using nested loops (prints an extra newline at the end):

awk '{for(i=1;i<=2;i++){for(j=i;j<=NF;j+=2)print $j;print ""}}'

Doesn't print an extra newline:

awk '{for(i=1;i<=2;i++){for(j=i;j<=NF;j+=2)print $j;if(i==1)print ""}}'

For comparison, paxdiablo's version with all unnecessary characters removed (1, 9 or 11 more characters):

awk '{for(i=1;i<=NF;i+=2)print $i;print "";for(i=2;i<=NF;i+=2)print $i}'

Here's an all-Bash version:

d=(abc edf xyz rfg yeg udh)
i="0 2 4 1 3 5"
for w in $i
do
    echo ${d[$w]}
    [[ $w == 4 ]]&&echo
done
Dennis Williamson
+3  A: 

Another Perl 5 version:

#!/usr/bin/env perl
use Modern::Perl;
use List::MoreUtils qw(part);

my $line = 'abc edf xyz rfg yeg udh';

my @fields = split /\s+/, $line; # split on whitespace

# Divide into odd and even-indexed elements
my $i = 0;
my ($first, $second) = part { $i++ % 2 }  @fields;

# print them out
say for @$first;
say '';          # Newline
say for @$second;
brunov
I'd never noticed `part`, but it's exactly what I wanted to be able to do here (`grep`, but keep both the passes and the fails, each in its own returned array). Thanks.
Telemachus
A: 

Ruby versions for comparison:

ARGF.each do |line|
  groups = line.split
  0.step(groups.length-1, 2) { |x| puts groups[x] }
  puts
  1.step(groups.length-1, 2) { |x| puts groups[x] }
end

ARGF.each do |line|
  groups = line.split
  puts groups.select { |x| groups.index(x) % 2 == 0 }
  puts
  puts groups.select { |x| groups.index(x) % 2 != 0 }
end
Telemachus
+2  A: 

A shame that the previous perl answers are so long. Here are two perl one-liners:

echo 'abc edf xyz rfg yeg udh'|
  perl -naE '++$i%2 and say for @F; ++$j%2 and say for "",@F'

On older versions of perl (without "say"), you may use this:

echo 'abc edf xyz rfg yeg udh'|
  perl -nae 'push @{$a[++$i%2]},"$_\n" for "",@F; print map{@$_}@a;'
Yaakov Belch
A: 
$ echo 'abc edf xyz rfg yeg udh' |awk -vRS=" " 'NR%2;NR%2==0{_[++d]=$0}END{for(i=1;i<=d;i++)print _[i]}'
abc
xyz
yeg
edf
rfg
udh

For newlines, i leave it to you to do yourself.

ghostdog74
+1  A: 

My attempt in haskell:

Prelude> (\(x,y) -> putStr $ unlines $ map snd (x ++ [(True, "")] ++ y)) $ List.partition fst $ zip (cycle [True, False]) (words "abc edf xyz rfg yeg udh")
abc
xyz
yeg

edf
rfg
udh
Prelude>
Wei
A: 

Here is yet another way, using Bash, to manually rearrange words in a line - with previous conversion to an array:

echo 'abc edf xyz rfg yeg udh' | while read tline; do twrds=($(echo $tline)); echo -e "${twrd[0]} \n${twrd[2]} \n${twrd[4]} \n\n ${twrd[1]} \n${twrd[3]} \n${twrd[5]} \n" ; done 

Cheers!

sdaau
This limits to just 5 words in a line and if the number of words increases.this will not work.i just showed an example and its not always the same.
Vijay Sarathi
The original problem formulation does not state anything about "number of words" increasing.Cheers!
sdaau