JohnBeckett (talk | contribs) (Some cleanups and set jump list.) |
(Add instructions re: optional range) Tag: Source edit |
||
(6 intermediate revisions by 4 users not shown) | |||
Line 14: | Line 14: | ||
==Using bash== |
==Using bash== |
||
− | The bash shell provides the RANDOM environment variable that gives a random integer from 0 to 32767 inclusive, on many Linux systems. Since < |
+ | The bash shell provides the RANDOM environment variable that gives a random integer from 0 to 32767 inclusive, on many Linux systems. Since <code>0G</code> jumps to the last line, this variable provides line numbers effectively from 1 to 32768 inclusive, and if the number of lines in the buffer is 32768 or less, the following can be used to define a command such that <code>:RandomLine</code> will jump to a random line in the buffer: |
<pre> |
<pre> |
||
− | :command! RandomLine execute 'normal! '.(system(' |
+ | :command! RandomLine execute 'normal! '.(system('/bin/bash -c "echo -n $RANDOM"') % line('$')).'G' |
</pre> |
</pre> |
||
==Using urandom== |
==Using urandom== |
||
− | On Linux, random bytes can be read from < |
+ | On Linux, random bytes can be read from <code>/dev/urandom</code>. The following takes three such bytes (<code>-N3</code>) which results in a random integer from 0 to 16,777,215 inclusive. Using more than three bytes might give integer overflow with a negative result (not a problem for <code>G</code> but undesirable if used for something else). |
− | The following defines a command such that < |
+ | The following defines a command such that <code>:RandomLine</code> will jump to a random line in the buffer: |
<pre> |
<pre> |
||
:command! RandomLine execute 'normal! '.(matchstr(system('od -vAn -N3 -tu4 /dev/urandom'), '^\_s*\zs.\{-}\ze\_s*$') % line('$')).'G' |
:command! RandomLine execute 'normal! '.(matchstr(system('od -vAn -N3 -tu4 /dev/urandom'), '^\_s*\zs.\{-}\ze\_s*$') % line('$')).'G' |
||
</pre> |
</pre> |
||
− | The < |
+ | The <code>matchstr()</code> strips leading and trailing whitespace, including newlines, from the result of calling <code>system()</code> (the leading whitespace must be removed since Vim, when converting a string to a number, gives zero if the string does not start with a digit). The <code>od</code> (octal dump) utility reads 3 bytes from <code>urandom</code> and outputs the text equivalent of a 4 byte unsigned integer (<code>-tu4</code>) with no lines marked and no addresses (<code>-vAn</code>). |
==Using Ruby== |
==Using Ruby== |
||
Line 47: | Line 47: | ||
Usage examples: |
Usage examples: |
||
− | *< |
+ | *<code>:RandomLine</code> jump to a random line from the first to the last inclusive. |
− | *< |
+ | *<code>:.,$RandomLine</code> jump to a random line from the current line (<code>.</code>) to the last line (<code>$</code>) inclusive. |
− | *< |
+ | *<code>:?^=?,/^=/RandomLine</code> jump to a random line within the current section, where each section starts with a header having "<code>=</code>" as the first character. |
==Plugins== |
==Plugins== |
||
One can utilize Dr. Chip's [http://www.drchip.org/astronaut/vim/index.html#RNDM random number generator]. |
One can utilize Dr. Chip's [http://www.drchip.org/astronaut/vim/index.html#RNDM random number generator]. |
||
+ | |||
+ | Here is the RandomLine command using this random number generator: |
||
+ | <pre> |
||
+ | function! RandomLine() range |
||
+ | let first_line = a:firstline |
||
+ | let last_line = a:lastline |
||
+ | let rndline = Urndm(first_line, last_line) |
||
+ | execute 'normal! '.rndline.'G' |
||
+ | endfunction |
||
+ | command! -range=% RandomLine <line1>,<line2>call RandomLine() |
||
+ | </pre> |
||
+ | It takes an optional range, or if no range is given, it defaults to the entire file. |
||
==Comments== |
==Comments== |
||
Line 58: | Line 70: | ||
:I don't actually jump to the lines, but I DO have a command that fires on buffer load to close approximately half of the folds in the window. For small files, it loops over all lines and sets the foldlevel to the average. For large files (over 10000 lines or so, accessed over the network) this can take a while; so I've used a random number generator to generate a few thousand random line numbers and gotten the foldlevel at each of them to average out instead. It needs to be random enough to get a good statistical sample, though probably I could have just sampled at intervals instead. --[[User:Fritzophrenic|Fritzophrenic]] 16:00, April 6, 2012 (UTC) |
:I don't actually jump to the lines, but I DO have a command that fires on buffer load to close approximately half of the folds in the window. For small files, it loops over all lines and sets the foldlevel to the average. For large files (over 10000 lines or so, accessed over the network) this can take a while; so I've used a random number generator to generate a few thousand random line numbers and gotten the foldlevel at each of them to average out instead. It needs to be random enough to get a good statistical sample, though probably I could have just sampled at intervals instead. --[[User:Fritzophrenic|Fritzophrenic]] 16:00, April 6, 2012 (UTC) |
||
:And I was generating random records for an application. Say, I found company names, human names from internet, and I opened both files in split view. To create a random match between people names and company names I wanted to record @ macro and run it n times in order to collect the (simple) database records in another buffer. I could use another tool (like Python) for that but I have a hammer in my hand and everything looking like... :-) --[[User:Udslk|Udslk]] 12:13, April 7, 2012 (UTC) |
:And I was generating random records for an application. Say, I found company names, human names from internet, and I opened both files in split view. To create a random match between people names and company names I wanted to record @ macro and run it n times in order to collect the (simple) database records in another buffer. I could use another tool (like Python) for that but I have a hammer in my hand and everything looking like... :-) --[[User:Udslk|Udslk]] 12:13, April 7, 2012 (UTC) |
||
+ | :I sort of got an use or this very recently. I had a really big csv file of about 500000 records and I wanted to reduce it by randomly removing records. So, this can be useful for that. Not a great use case but this would have solved my problem. - [http://vim.wikia.com/wiki/User_talk:Durgaswaroop Swaroop] 13:45, July 7, 2016 (IST) |
||
:It may be useless when editing source code, but I've got a text file of URLs, todos, notes gathered over some time without access to a wiki and I want an unbiased way to spend some time every now sorting portions of the file. |
:It may be useless when editing source code, but I've got a text file of URLs, todos, notes gathered over some time without access to a wiki and I want an unbiased way to spend some time every now sorting portions of the file. |
Latest revision as of 06:33, 11 February 2021
created August 31, 2011 · complexity basic · author Udslk · version 7.0
For test data aggregation work, it may be desirable to jump to a random line in the current buffer. Here are some techniques for doing that. These rely on an external program to generate the random number, as Vim has no built-in random function (although the current time can be used as a crude form of "random" that is adequate for some purposes, see here).
Using bash[]
The bash shell provides the RANDOM environment variable that gives a random integer from 0 to 32767 inclusive, on many Linux systems. Since 0G
jumps to the last line, this variable provides line numbers effectively from 1 to 32768 inclusive, and if the number of lines in the buffer is 32768 or less, the following can be used to define a command such that :RandomLine
will jump to a random line in the buffer:
:command! RandomLine execute 'normal! '.(system('/bin/bash -c "echo -n $RANDOM"') % line('$')).'G'
Using urandom[]
On Linux, random bytes can be read from /dev/urandom
. The following takes three such bytes (-N3
) which results in a random integer from 0 to 16,777,215 inclusive. Using more than three bytes might give integer overflow with a negative result (not a problem for G
but undesirable if used for something else).
The following defines a command such that :RandomLine
will jump to a random line in the buffer:
:command! RandomLine execute 'normal! '.(matchstr(system('od -vAn -N3 -tu4 /dev/urandom'), '^\_s*\zs.\{-}\ze\_s*$') % line('$')).'G'
The matchstr()
strips leading and trailing whitespace, including newlines, from the result of calling system()
(the leading whitespace must be removed since Vim, when converting a string to a number, gives zero if the string does not start with a digit). The od
(octal dump) utility reads 3 bytes from urandom
and outputs the text equivalent of a 4 byte unsigned integer (-tu4
) with no lines marked and no addresses (-vAn
).
Using Ruby[]
The following variation requires Ruby and a Vim compiled with support for Ruby.
:command! RandomLine ruby Vim::command 'normal! ' + ((rand $curbuf.length) + 1).to_s + 'G'
The following alternative defines a command that works with ranges:
function! RandomLine() range ruby first_line = (VIM::evaluate 'a:firstline').to_i ruby last_line = (VIM::evaluate 'a:lastline').to_i ruby VIM::command(((rand last_line - first_line + 1) + first_line).to_s) ruby VIM::command("mark '") endfunction command! -range=% RandomLine <line1>,<line2>call RandomLine()
Usage examples:
:RandomLine
jump to a random line from the first to the last inclusive.:.,$RandomLine
jump to a random line from the current line (.
) to the last line ($
) inclusive.:?^=?,/^=/RandomLine
jump to a random line within the current section, where each section starts with a header having "=
" as the first character.
Plugins[]
One can utilize Dr. Chip's random number generator.
Here is the RandomLine command using this random number generator:
function! RandomLine() range let first_line = a:firstline let last_line = a:lastline let rndline = Urndm(first_line, last_line) execute 'normal! '.rndline.'G' endfunction command! -range=% RandomLine <line1>,<line2>call RandomLine()
It takes an optional range, or if no range is given, it defaults to the entire file.
Comments[]
It would be nice if someone could provide a clue why jumping to a random line might be useful. I can imagine wanting a program to fetch a random line from a file for some kind of test input, but why use Vim for that? JohnBeckett 08:15, April 6, 2012 (UTC)
- I don't actually jump to the lines, but I DO have a command that fires on buffer load to close approximately half of the folds in the window. For small files, it loops over all lines and sets the foldlevel to the average. For large files (over 10000 lines or so, accessed over the network) this can take a while; so I've used a random number generator to generate a few thousand random line numbers and gotten the foldlevel at each of them to average out instead. It needs to be random enough to get a good statistical sample, though probably I could have just sampled at intervals instead. --Fritzophrenic 16:00, April 6, 2012 (UTC)
- And I was generating random records for an application. Say, I found company names, human names from internet, and I opened both files in split view. To create a random match between people names and company names I wanted to record @ macro and run it n times in order to collect the (simple) database records in another buffer. I could use another tool (like Python) for that but I have a hammer in my hand and everything looking like... :-) --Udslk 12:13, April 7, 2012 (UTC)
- I sort of got an use or this very recently. I had a really big csv file of about 500000 records and I wanted to reduce it by randomly removing records. So, this can be useful for that. Not a great use case but this would have solved my problem. - Swaroop 13:45, July 7, 2016 (IST)
- It may be useless when editing source code, but I've got a text file of URLs, todos, notes gathered over some time without access to a wiki and I want an unbiased way to spend some time every now sorting portions of the file.