I have a graph data in a file with each line containing the source and destination node of an edge. I want to assign a random weight between [1, 10] for each edge to test my graph algorithm. How can i do that in vim?

Graph data:

1 2
2 3
1 5

Data along with weights(Expected Output)

1 2 5
2 3 3
1 5 9

The last column is the weight of each edge.


You can do it with a macro :

:r!echo $RANDOM^Mld$kJ

Decomposing the macro :

:r!echo $RANDOM^M

Note : ^M is the litteral <CR>, so you should press <CR> instead of ^M when you record your macro.

This insert in a new line a random number (you should look at this post for more infos).

l       " go right
 d      " delete ... 
  $     " ... to the end of the line (leaving only the first digit)
   k    " go up
    J   " join the line below

Note : As stated by @Doorknob :

Bash's $RANDOM returns a random number from 0 to 32767

So to keep the last digit instead of the first one, you can replace the ld$ part by : vehx. I think that a random number generation should be put in a function and be carefully handled.

  • The above macro is generating a random number with 4 or 5 digits. Along with the numbers the characters "^Mld" is appended. But it is not appending to the end of the line. It is creating a new line. I guess the commands ld$ and kJ is not working. Is there any dependence where those commands might not work? Aug 18 '15 at 15:22
  • The ^M stands for the litteral <CR>, I edited my answer to be more clear. I don't understand why the ld$kJ part doesn't work as it's basic vim commands ...
    – nobe4
    Aug 18 '15 at 15:24
  • 1
    -1, this is very, very far from random. Bash's $RANDOM returns a random number from 0 to 32767, so your results will be heavily biased towards 0, 1, and 2.
    – Doorknob
    Aug 20 '15 at 11:23
  • I didn't know that, let me update my answer.
    – nobe4
    Aug 20 '15 at 11:24

As long as you don't mind the quality of the random process generation:

:%s/\s*$/\=' ' . (1 + str2nr(matchstr(reltimestr(reltime()), '\v\.@<=\d+')[1:]) % 10)/

It basically replaces the end of each line, and all the trailing spaces, with a single space followed by (current time microseconds % 10) + 1, where % is the remainder/modulo operation.

random ... reference


This is the gist of it (assuming UNIX environment):

:g//read! echo $RANDOM

If you want the number to be between 1 and 10:

:g//read! echo $(( 1 + $RANDOM % 10 ))

If you want to do this for a section of the file, just select the lines in visual line mode before typing the first command, and press gv before typing the second.

  • Did you miss the $ for the pattern in :g command? Aug 18 '15 at 16:13
  • Sorry my mistake. It works. Aug 18 '15 at 16:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.