2016-11-26 81 views

回答

7

使用decorate-sort-undecorate模式的一种形式,awk你可以这样做:

$ seq 10 | awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}' | sort -n | cut -c8- 
8 
5 
1 
9 
6 
3 
7 
2 
10 
4 

对于一个文件,你会怎么做:

$ awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}' SORTED.TXT | sort -n | cut -c8- > SHUFFLED.TXT 

cat管道开始处的文件。

这个工作方式是生成一列000000999999之间的随机数字(装饰);在该列上排序(排序);然后删除列(undecorate)。这应该在排序不理解数字的平台上工作,方法是生成一个具有前导零的列以进行词典排序。

您可以增加随机化,如果需要的话,在几个方面:

  1. 如果你的平台的sort了解数值(POSIX,GNU和BSD这样做),你可以做awk 'BEGIN{srand();} {printf "%0.15f\t%s\n", rand(), $0;}' FILE.TXT | sort -n | cut -f 2-使用接近双浮子随机表示。

  2. 如果您仅限于词典排序,只需将两个调用合并到一个列中,如下所示:awk 'BEGIN{srand();} {printf "%06d%06d\t%s\n", rand()*1000000,rand()*1000000, $0;}' FILE.TXT | sort -n | cut -f 2-它提供了一个12位数的随机组合。

+0

尼斯洗牌 多TB的文本文件准洗牌算法。因为'sort'分成多个文件来处理大于内存的内容(GNU版本,无论如何),这实际上应该工作。 –

+0

+1 - 好主意。请注意,因为'sort'执行稳定的排序,所以这不会是100%完美的洗牌:如果A行在输入的B行之前,这种方法稍微有可能在行B之前将A行放在输出中。为了解决这个问题,你可以通过编写诸如'seq 10 |的东西来反转编号和混洗grep -n''| sort -R |切掉-d:-f2-'代替。 (但即使没有这种变化,我认为它可能是好的:我认为它应该非常接近随机排序。) – ruakh

+0

@ruakh:谢谢。你是对的 - 由于“排序”具有稳定的排序,所以它略有维持秩序的倾向。它具有0到1000000之间的随机数字,因此这只会是连续两行中相同随机数的问题。另一种更加随机的方法是添加更多数字或第二列随机数字。 – dawg

3

计数行(wc -l)并按随机顺序生成与行号相对应的数字列表 - 可能是通过生成临时文件中的数字列表(使用/tmp/,通常位于RAM中,因此速度相对较快)。然后按照混洗号码的顺序将每个号码对应的行复制到目标文件中。

由于在文件中寻找换行符的数量,这样做效率会很低,但它几乎适用于任何大小的文件。

0

如何: perl <large-input-file -lne 'print rand(), "\t", $_' | sort | perl -lpe 's/^.*?\t//' >shuffled-output-file

0

如果文件中有什么可以装入内存大小的几个数量级之内,一个选择是随机分配中(比如说)1000个临时文件中的行,然后洗牌每个这些文件并连接结果:

perl -we ' my $NUM_FILES = 1000; 
      my @fhs; 
      for (my $i = 0; $i < $NUM_FILES; ++$i) { 
      open $fh[$i], "> tmp.$i.txt" 
       or die "Error opening tmp.$i.txt: $!"; 
      } 
      while (<>) { 
      $fh[int rand $NUM_FILES]->print($_); 
      } 
      foreach my $fh (@fhs) { 
      close $fh; 
      } 
     ' < input.txt \ 
&& \ 
for tmp_file in tmp.*.txt ; do 
    shuf ./"$tmp_file" && rm ./"$tmp_file" 
done > output.txt 

(当然,也将在临时文件—的尺寸有一些变化,他们不会全部是正好千分之一原始文件—的大小,因此,如果您使用这种方法,你需要在更多方面犯错,更小的文件)。

+0

赦免最初的误读 - 我希望downvoter不相信我错误的分析。这是一个完全合理的方法。 –

+0

@CharlesDuffy:不用担心。我*猜测* downvoter实际上是l'L'l。 (即使不是,我现在认为dawg的答案比我的答案更好,所以我不太关心这个答案。:-P) – ruakh

相关问题