如何在vim中对列表进行洗牌?

34

在 Vim 中,最好的洗牌列表的方法是什么?

我正在尝试在 vim 中随机排序行(使用 vimscript)。 为此,我创建了一个包含所有行号的列表(在我的选择中)。

例如,如果我从第 10 行选到第 20 行,我的列表将是:

mylist = ['10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20']

我想随机排序这些行,并通过for循环将它们放回到同一个选择区域的新序列中。 为了实现这个目标,我想多次打乱列表,但不知道如何打乱。

另一种解决方案是从上次随机选择的位置选取索引。

无法确定最佳方法。

我知道可以使用Python、Ruby或其他语言来对行进行排序,但我不想安装它们。 我想使用vimscript实现以上功能。


有用:本地 Vim 随机数脚本。我看你已经了解那里的算法了。 - glts
1
对于 Vim 脚本中更加强大的随机数生成器,还有 Rndm - glts
昨天我查看了本地Vim随机脚本,但发现值并不是随机创建的(请参见我的评论)。我还查看了Chip Campbell的Rndm脚本,但发现排序也不是随机的(而且,代码太多了)。 - Reman
4个回答

47
你可以采用“UNIX风格”,使用coreutils包中的shuf命令:
:10,20!shuf<CR>

15
我选择的武器是::'<,'>!sort -R,或使用来自randomize-linesrl - sehe
1
@sehe,感谢您的回复。在我看来,“sort!-R”并不是一个非常好的随机排序(这是我以前的随机排序命令)。“rl”在我的电脑上无法工作。什么都没有发生。 - Reman
4
你有什么实质性的声明可以解释为什么 :!sort -R 不能进行良好的随机排序吗?因为我刚刚比较了 sort.cshuf.c 的实现,必须承认 sort.c 更加多功能(例如尝试使用 sort -uR,或使用特定的键)。 - sehe
perl -M"List::Util qw(shuffle)" -e "print shuffle <>" input.txt > output.txt - Alexander Farber

20

2019年更新:

现在,在 osx 中的 sort 命令中已经包含了一个 -R 标志,所以你只需执行以下命令:

:'<,'>!sort -R

=== 之前的回答: ===

osx 中的 sort 命令没有 -R 标志,所以需要按照以下步骤操作:

首先,安装 coreutils:

brew install coreutils

然后在 vim 中选择需要排序的行,运行以下命令:

:'<,'>!gsort -R


2
截至2019年,在macOS中,sort命令有一个-R标志,因此不再需要使用gsort。 - take
我在Linux上使用了 :%!sort -R - Edgard Leal

4

如果你需要一个均匀随机数生成器,我不知道vim是否能够提供本地支持(或者你可以求助于一些插件)。然而,如果你只是想打乱一些行的顺序,你可以尝试这个函数:

function! Random()
    return reltimestr(reltime())[-2:]
endfunction

该函数返回当前时间戳的毫秒数的最后两位。

要对行进行随机排序,您可以(例如对整个缓冲区)执行以下操作:

%s/^/\=Random() . " "

那么。
:sor n

最后删除添加的前缀:
%s/^\S* //

当然,您可以使用<bar>命令链接上述命令。
%s/^/\=Random() . " "/|sor n|%s/^\S* //

如果不想创建函数,可以将随机数部分写入你的:s中:

%s/^/\=reltimestr(reltime())[-2:] . " "/|sor n|%s/^\S* //

如果我使用“seq 30”生成值为1-30的30行进行测试,
第一次的结果是:
2
26
12
17
8
22
27
3
13
18
23
9
28
4
14
19
1
24
10
29
5
6
15
20
25
30
11
16
7
21

第二次结果:

4
22
25
28
6
9
18
12
15
1
3
5
21
24
27
30
8
11
17
14
2
20
23
26
29
7
10
16
13
19

希望这能有所帮助。


非常感谢您,肯特。我注意到它每8、9、10行分组一次。请参阅我的评论:https://dev59.com/gGcs5IYBdhLWcg3wk06X 我最终决定使用shuf命令(我已经安装了cygwin),尽管我更喜欢只使用vimscript。这个命令同样可以搜索随机值,而且非常好用 exe 'normal! '.(system('sh -c "echo -n $RANDOM"') % 1000),但对于每一行都这样做,会不停地闪烁我的VIM窗口(使用bash shell)。 - Reman
1
我已经回答了,假设您没有外部的 shuf、sort 或者 shell 中的 $RANDOM 变量可用。如果如你所说,你有这些工具,shuf 将是最直接的方式,我也会选择这种方式。我的命令有点变通。 - Kent
而且,我看不到“它将每8、9、10行分组”的效果。您可以在我的答案中检查两次运行的结果。我查看了其他问题和答案,我们得出了相同的想法,但使用了不同的数字。 - Kent
Kent,也许我使用的是与你不同的时间标准?当我在我的电脑上测试时,我清楚地看到了一组行。 - Reman

2
你可以编写一个Python脚本来帮助在vim中进行随机操作。 我创建了一个名为pyrandom.py的Python文件。然后添加执行模式,chmod +x pyrandom.py,最后需要做的是将pyrandom.py的目录添加到PATH中,你可以暂时运行export PATH=$PATH:/directory/to/pyrandom.py/来添加到PATH中。
现在,你可以在vim中选择行,然后运行: :'<,'>!pyrandom.py pyrandom.py文件的内容:
#!/usr/bin/python
import sys
import random

all_lines = []
for line in sys.stdin:
    all_lines.append(line.rstrip('\n'))

random.shuffle(all_lines)

for line in all_lines:
    print line

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接