UWSCでCSVファイルをソートする
公式掲示板より
aaa.csvから数値データを取り出して(3列目-4列目)/9列目の計算結果を元にソートをかけたい
気が向いたので、考えてみた。
答え1
LinersさんのヒントにQSORTを使うものがあるので使ってみた。
DIM fid = FOPEN("aaa.csv", F_READ) CONST COLS = 9 DIM rows = FGET(fid, F_LINECOUNT), r, c DIM d[rows][COLS], s[1][rows] FOR r = 1 TO rows FOR c = 1 TO COLS d[r][c] = FGET(fid, r, c) NEXT s[0][r] = ROUND((d[r][3] - d[r][4]) / d[r][9], -4) s[1][r] = r NEXT FCLOSE(fid) QSORT(s[0], 0, s[1]) DIM fidw = FOPEN("bbb.csv", F_WRITE) FOR r = 1 TO rows FOR c = 1 TO COLS FPUT(fidw, d[s[1][r]][c], r, c) NEXT NEXT FCLOSE(fidw)
この方法でも充分良いと思われる。
質問者さんのスクリプトにも似ているので、理解できると思われる。
強いて難点を挙げると、
答え2
内部メモリーを削減を考えてみる。
DIM fid = FOPEN("aaa.csv", F_READ) DIM fidw = FOPEN("bbb.csv", F_WRITE) DIM rows = FGET(fid, F_LINECOUNT), r, c CONST SEP = "," CONST COLS = 9 DIM s = SPLIT(EMPTY), i, t, buf FOR r = 1 TO rows t = ROUND((FGET(fid, r, 3) - FGET(fid, r, 4)) / FGET(fid, r, 9), -4) c = LENGTH(s) - 1 FOR i = 0 TO c IF VAL(s[i]) > t THEN BREAK NEXT buf = "" IF i > 0 THEN buf = JOIN(SLICE(s, 0, i - 1), SEP) IF LENGTH(buf) THEN buf = buf + SEP buf = buf + t IF i <= c THEN buf = buf + SEP + JOIN(SLICE(s, i, c), SEP) s = SPLIT(buf, SEP) FPUT(fidw, FGET(fid, r, 1), i + 1, F_INSERT) FOR c = 2 TO COLS FPUT(fidw, FGET(fid, r, c), i + 1, c) NEXT NEXT FCLOSE(fidw) FCLOSE(fid)
ついでに、安定ソートも目指した。
IF VAL(s[i]) > t THEN BREAK
として確保。
JOIN/SLICEがトリックくさい。
答え3
ソートと言えば、SQL!
DIM db = CREATEOLEOBJ("ADODB.Connection") db.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=.;Extended Properties=<#DBL>text;HDR=No;FMT=Delimited<#DBL>") DIM rs = db.Execute("SELECT * FROM aaa.csv ORDER BY ((F3-F4)/F9)") DIM fidw = FOPEN("bbb.csv", F_WRITE), c, r = 1 WHILE !rs.EOF FOR c = 1 TO 9 FPUT(fidw, rs.Fields[c].Value, r, c) NEXT r = r + 1 rs.MoveNext() WEND FCLOSE(fidw)
Microsoft.Jet.OLEDBを使用。
Schema.iniを使えば、Microsoft Text Driverでも可能。
ま、Schema.iniを使いたくなかったので。
CSVの内容によっては、変なデータ変換がかかるので、Schema.iniでMicrosoft Text Driverにするのが推奨。
ソートはODBC任せになったので、トリックは消えたが、安定ソートではなくなった模様、、、。
工夫すれば安定ソートにできると思うけど、もう眠い。
いずれも微妙に問題点がありますね。
まー、いずれの方法でも細かくつめればよいのですけどね。