Shellスクリプトがファイルの内容を無秩序に並べるための様々な方法(シャッフル問題)を実現します。
5265 ワード
トランプを洗ってもいいですか?きれいに洗うことができますし、早く洗うこともできます。つまり、一つのファイルに対してどのように効率的に乱序配列を実現しますか?
ChinaUnixは確かにシェルの達人が集まっているところです。あなたが欲しい問題があれば、そこに行ってもほぼ答えが見つかります。r 2007は、ShellのRANDOM変数を利用して元のファイルの行にランダムな行番号を付けて、この乱数行番号に基づいて並べ替えて、仮加算された行番号をフィルタリングして、このように操作して得られた新しいファイルはランダムに「洗」されたものに相当します。
もう一つは巧妙な方法からのawkによるシャッフル効果を実現するランダムファイルのソートコード分析(蓉元に貼り付けられています。また、このスレッドの一つここですです。アカウントを登録していないなら、引き続き討論するまで精華区の文章を調べられます。)です。
-------------------------------------------
シャッフルについては、実はもう一つのいいshell解法があります。ここではAWKに基づく三つの方法をあげます。
方法その1:お手盛り
寒例法と同様に、印刷済みの行の出現回数を記録するためのハッシュを構築し、回数が多い場合は処理を行わないと重複を防ぐことができますが、システムのオーバーヘッドを増大させるという欠点があります。
配列の下付き変換に基づく方法、すなわち、行列で各行のコンテンツを格納し、配列下付きの変換によって配列の内容を交換することによって、効率が良い方法がある。
三つの方法の中で一番いいです。
AWKにおけるハッシュの特性を利用して、ランダムで重複しないハッシュ関数を構築すればいいです。一つのファイルのラインnumberは唯一無二なので、使用します。
乱数+ライン当たりnumber ------対応--> その一行の内容
すなわち、作成されたランダム関数です。
したがって、
テスト環境:
PM 1.4 GHz CPU,40 Gハードディスク,メモリ256 MのLAPTOP
SUSE 9.3 GNU bash version 3.0.16 GNU Awk 3.1.4
50万行のランダムファイルを作成しました。約38 Mです。
シャッフルに使う時間:
方法二のテスト:
次に方法3の効率を調べます。
-------------------------------------------
flyflyから書いたpythonバージョンの乱順コードを添付します。
ChinaUnixは確かにシェルの達人が集まっているところです。あなたが欲しい問題があれば、そこに行ってもほぼ答えが見つかります。r 2007は、ShellのRANDOM変数を利用して元のファイルの行にランダムな行番号を付けて、この乱数行番号に基づいて並べ替えて、仮加算された行番号をフィルタリングして、このように操作して得られた新しいファイルはランダムに「洗」されたものに相当します。
while read i;do echo "$i $RANDOM";done<file|sort -k2n|cut -d" " -f1
もちろんソースファイルの各行の内容が複雑であれば、このコードを書き換えなければなりませんが、処理のコツを知っていれば、残りの問題は解決しにくいです。もう一つは巧妙な方法からのawkによるシャッフル効果を実現するランダムファイルのソートコード分析(蓉元に貼り付けられています。また、このスレッドの一つここですです。アカウントを登録していないなら、引き続き討論するまで精華区の文章を調べられます。)です。
-------------------------------------------
シャッフルについては、実はもう一つのいいshell解法があります。ここではAWKに基づく三つの方法をあげます。
方法その1:お手盛り
寒例法と同様に、印刷済みの行の出現回数を記録するためのハッシュを構築し、回数が多い場合は処理を行わないと重複を防ぐことができますが、システムのオーバーヘッドを増大させるという欠点があります。
awk -v N=`sed -n '$=' data` '
BEGIN{
FS="
";
RS=""
}
{
srand();
while(t!=N){
x=int(N*rand()+1);
a[x]++;
if(a[x]==1)
{
print $x;t++
}
}
}
' data
方法二:変換配列の下付き変換に基づく方法、すなわち、行列で各行のコンテンツを格納し、配列下付きの変換によって配列の内容を交換することによって、効率が良い方法がある。
#! /usr/awk
BEGIN{
srand();
}
{
b[NR]=$0;
}
END{
C(b,NR);
for(x in b)
{
print b[x];
}}
function C(arr,len,i,j,t,x){
for(x in arr)
{
i=int(len*rand())+1;
j=int(len*rand())+1;
t=arr[i];
arr[i]=arr[j];
arr[j]=t;
}
}
方法3:ハッシュ三つの方法の中で一番いいです。
AWKにおけるハッシュの特性を利用して、ランダムで重複しないハッシュ関数を構築すればいいです。一つのファイルのラインnumberは唯一無二なので、使用します。
乱数+ライン当たりnumber ------対応--> その一行の内容
すなわち、作成されたランダム関数です。
したがって、
awk 'BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}' data
実は皆さんが心配しているメモリーの使用はあまり気にしなくてもいいです。テストをしてもいいです。テスト環境:
PM 1.4 GHz CPU,40 Gハードディスク,メモリ256 MのLAPTOP
SUSE 9.3 GNU bash version 3.0.16 GNU Awk 3.1.4
50万行のランダムファイルを作成しました。約38 Mです。
od /dev/urandom |dd count=75000 >data
効率の低い方法で言ってください。シャッフルに使う時間:
time awk -v N=`sed -n '$=' data` '
BEGIN{
FS="
";
RS=""
}
{
srand();
while(t!=N){
x=int(N*rand()+1);
a[x]++;
if(a[x]==1)
{
print $x;t++
}
}
}
' data
結果(ファイルの内容は省略):
real 3m41.864s
user 0m34.224s
sys 0m2.102s
だから、効率は何とか受け入れられます。方法二のテスト:
time awk -f awkfile datafile
結果(ファイルの内容は省略):
real 2m26.487s
user 0m7.044s
sys 0m1.371s
効率は第一より明らかに良い。次に方法3の効率を調べます。
time awk 'BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}' data
結果(ファイルの内容は省略):
real 0m49.195s
user 0m5.318s
sys 0m1.301s
38 Mの書類にとってはかなりいいです。-------------------------------------------
flyflyから書いたpythonバージョンの乱順コードを添付します。
#coding:gb2312
import sys
import random
def usage():
print "usage:program srcfilename dstfilename"
global filename
filename = ""
try:
filename = sys.argv[1]
except:
usage()
raise()
#open the phonebook file
f = open(filename, 'r')
phonebook = f.readlines()
print phonebook
f.close()
#write to file randomly
try:
filename = sys.argv[2]
except:
usage()
raise()
f = open(filename, 'w')
random.shuffle(phonebook)
f.writelines(phonebook)
f.close()