2016-11-26 78 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

相關問題