How to split a string and change its elements?

I have some data on one line as below

abc edf xyz rfg yeg udh 

I want to present the data below:

 abc xyz yeg edf rfg udh 

so that alternate fields are printed alternately with a newline separator. Are there any liners for this?

+2
unix shell awk perl sed
Oct 23 '09 at 4:52
source share
12 answers

The following awk script can do this:

 > 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 
+6
Oct 23 '09 at 4:59
source share

Python in the same spirit as awk above (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 (pipe down to it, which is identical):

 $ python -c 'f=raw_input().split(); print "\n".join(f[::2] + [""] + f[1::2])' 
+4
Oct 23 '09 at 5:16
source share

Another version of Perl 5:

 #!/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; 
+3
Oct 23 '09 at 13:02
source share

It's a shame that previous perl answers are so long. Here are two perl single-line:

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

In older versions of perl (without "say") you can use this:

 echo 'abc edf xyz rfg yeg udh'| perl -nae 'push @{$a[++$i%2]},"$_\n" for "",@F; print map{@$_}@a;' 
+3
Oct 25 '09 at 12:08
source share

Just for comparison, here are a few Perl scripts for this (TMTOWTDI, after all). 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 make 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 have run out of ways to do this, so if any other smart Perlers come up with a different method, feel free to add one.

+2
Oct 23 '09 at 5:32
source share

Another solution for Perl:

 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 can even condense it into a real single-line layer:

 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], "");' 
+1
23 Oct '09 at 7:32
source share

Here's a 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}' 

A little longer (two more characters) using nested loops (prints an extra line of a new line at the end):

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

Does not print an extra line of a new line:

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

For comparison: the paxdiablo version with all unnecessary characters is deleted (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 is the 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 
+1
Oct 23 '09 at 7:36
source share

My attempt at 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> 
+1
Oct 26 '09 at 3:41
source share

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

0
Oct 23 '09 at 5:55
source share

Ruby options 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 
0
Oct 23 '09 at 14:13
source share
 $ 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 new lines, I leave this for you.

0
Oct 25 '09 at 14:17
source share

Here's another way, using Bash, to manually reorder the words in a string - with the 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 

Hurrah!

0
Sep 03 '10 at 12:32
source share



All Articles