Here's a way to do it within the same file using just Vim.
It involves some key-mapping. I came up with this once when I wanted to arrange several lists into table-like structures in simple text.
This relies on the } key (right curly-brace) to skip paragraph boundaries. (The braces are mirrored, btw: { skips towards the top of file and } towards the end.)
So... suppose you have a data file like this (this supposes that line#'s are turned on with :set nu):
+---------------
| 1 xxx (cursor on line#1)
| 2 yyy
| 3 zzz
| 4
| 5 kkk
| 6 qqq
| 7 ppp
+---------------
It is important that line #4 is an empty line (no whitespace),
I'll explain why in a moment.
Execute the following map command:
:map q mw}jdd'wpkJj
This binds the "q" key to a 12 character program, which I'll break down
in some detail below.
When you hit "q" it will execute that program; note that your cursor,
which started on line #1 is now on the next line, ready to hit "q" again.
You may have noticed there is a space character between "xxx kkk"; if you don't
want that then see "What About The Extra Space Character?" below, near the end.
+---------------
| 1 xxx kkk
| 2 yyy (cursor on line #2)
| 3 zzz
| 4
| 5 qqq
| 6 qqq
| ~
+---------------
Here's a breakdown of the mapping:
:map q mw}jdd'wpkJj
^
The colon gets you into command mode so we can issue the "map" command.
:map q mw}jdd'wpkJj
^^^^^
map q binds q with the following character sequence.
Note that "q" is just my usual "map to" key; you can use other keys. By default lowercase q is mapped to start macro
recording; since I rarely (never?) use that I find "q" more helpful for one-off utility macros.
You could also use uppercase Q (e.g. map Q) or a fnct key or so on.
Now whenever you press "q" (in navigation mode), vim will execute this series of keystrokes:
mw}jdd'wpkJj
Which of course looks like total gibberish, so I'll break it down action-by-action (with ^^'s below) to
make it easier to follow what is happening.
mw}jdd'wpkJj
^^
The mw MARKs a named location, the name here is 'w'. I use 'w' by default (I think of that
as my 'w'orking location. Any named location, from a-z would work, so long as you're consistent.
The 'w' will show up again in a bit when we want to return the cursor to this line.
mw}jdd'wpkJj
^
Here we have the right-curly } which jumps the cursor down to the next paragraph boundary; in other words,
this moves the cursor to the next empty line, which is line# 4 in our example. (This is why line #4 should
be an empty line; no whitespace, otherwise } won't consider it a boundary.)
mw}jdd'wpkJj
^
The j goes down one line; this is the old-school vi "hjkl" navigation.
You could probably use a down-arrow here as well, I find "j" somewhat
easier to read, and easier to use (because arrow keys aren't always in the
same place between various brands of laptop and desktop keyboards, but "hjkl" is Guaranteed
to always be on right hand side of any QWERTY keyboard's home-row (which helps my typing speed)).
Anyway, at this point, the cursor is on line# 5.
+---------------
| 1 xxx
| 2 yyy
| 3 zzz
| 4
| 5 kkk (cursor on line#5)
| 6 qqq
| 7 ppp
+---------------
mw}jdd'wpkJj
^^
The dd is the "delete line" edit command, so it deletes the current line,
which is line#5 with the "kkk" on it.
Deleting the line also puts it in the default paste buffer, which we'll use exploit
to bring "kkk" back to where we want it on line #1, next to "xxx".
mw}jdd'wpkJj
^^
The 'w (single-quote w) sequence jumps the cursor back to our bookmark for "w",
which puts the cursor on line#1.
mw}jdd'wpkJj
^
The lowercase "p" PUTS the current default buffer (with "kkk", as you'll recall) after the cursor.
Since the buffer contains what used to be line#5, our file briefly looks
like this now:
+---------------
| 1 xxx
| 2 kkk (cursor on line#2, after the freshly restored "kkk")
| 3 yyy
| 4 zzz
| 5
| 6 qqq
| 7 ppp
+---------------
Note how "kkk" has become line#2. (I can't easily illustrate
where the cursor goes there... it should really be at the beginning of line#2).
We're close but not quite there yet...
mw}jdd'wpkJj
^^
The lower-case k hops the cursor up to line#1 ("hjkl" navigation again),
and the uppercase J joins the next line onto the current line,
making our file look like this (cursor is still on line #1,
between the x's & the k's):
+---------------
| 1 xxx kkk (cursor on line #1, between 'xxx' and 'kkk')
| 2 yyy
| 3 zzz
| 4
| 5 qqq
| 6 ppp
+---------------
mw}jdd'wpkJj
^
The last j is "hjkl" navigation once more, which moves the
cursor down to line#2 which is handy because that is the next line
we want to apply q to.
Anyway way, it will look like this:
+---------------
| 1 xxx kkk
| 2 yyy (cursor on #2)
| 3 zzz
| 4
| 5 qqq
| 6 ppp
+---------------
If you hit "q" again and it will look
like this (note the curser is on line#3).
+---------------
| 1 xxx kkk
| 2 yyy qqq
| 3 zzz (cursor on #3)
| 4
| 5 ppp
+---------------
Rinse and repeat as necessary.
I find this handy for longer lists because it lets me
(fairly) painlessly build up columns.
Here's a longer example. Adding a blank line at row #7 causes "ggg" to stack first
in the next column. After getting down to "lll", jump
your cursor back up to line #1 ( left curly, {, works
well for that) and keep going with "mmm".
If you decide you don't quite like the way it is arranging, hold down on u (undo) for a bit and tweak where you "boundary" line is then start over.
This is one of those things that works much easier than
it takes effort to explain.
While I don't think I'd use it for joining thousands of rows I find it handy for dozens and occasionally hundreds.
+----------:---------------------------
| before : after
+----------:---------------------------
| 1 aaa : 1 aaa ggg mmm sss yyy
| 2 bbb : 2 bbb hhh nnn ttt zzz
| 3 ccc : 3 ccc iii ooo uuu
| 4 ddd : 4 ddd jjj ppp vvv
| 5 eee : 5 eee kkk qqq www
| 6 fff : 6 fff lll rrr xxx
| 7 :-------------------------
| 8 ggg
| 9 hhh
| 10 iii
| 11 jjj
| 12 kkk
| 13 lll
| 14 mmm
| 15 nnn
| 16 ooo
| 17 ppp
| 18 qqq
| 19 rrr
| 20 sss
| 21 ttt
| 22 uuu
| 23 vvv
| 24 www
| 25 xxx
| 26 yyy
| 27 zzz
+----------
What About The Extra Space Character?
Part of the Join command's behaviour is that it puts a space between lines that it joins.
If you don't want a space between "xxx kkk" you can
add a delete-command (x) to the string:
simple join (space char): :map q mw}jdd'wpkJj
join + x (kills space): :map q mw}jdd'wpkJxj
join w/comma: :map q mw}jdd'wpkJR,^[j
The "join + x" kills the space by using the x right after we join the two lines together. x in Navigation mode deletes whatever character the cursor happens to be on, which in this case was the offending space character.
The "join w/comma" replaces the space with a comma. That is mostly the same but we'll step through the last part which is just a bit different from the previous example.
:map q mw}jdd'wpkJR,^[j
^
The R places us into Edit mode (specifically Replace mode, which will overwrite any characters with what we type).
:map q mw}jdd'wpkJR,^[j
^
The , literally types a comma, which is overwrites the offending space at that point.
:map q mw}jdd'wpkJR,^[j
^^
And then ^[ signals an Escape character, which leaves Edit mode and puts us back in Navigation mode.
Now we're ready for the final j to take us down to the next line.
To map an escape character you need to hit ^Q (windows) or ^V (linux & unix) then press the Esc key
(if you don't, the Esc character will abort the command and your left wondering why your possibly complex map definition just vanished).
Here's the sequence you'd have to type to get it into Vim on Windows:
:map q mw}jdd'wpkJR,<Ctr-Q><Esc>j
So.
There are probably dozens of ways to do this sort of thing Vim.
When "field" delimiters matter, I usually put a simple unique sequence at the
end of every line with global search and replace, go ahead and join up the
columns the way I want and then replace-all to get the specific separator's that I want.
Anyway, this is just one example. I hope you found it interesting.