|
お世話になっております。 下記コードで重複が削除できるようですが
hash[fget(fp,i)]=1 でダミーの数字を指定する理由 fput(fp,hash[i, HASH_KEY]) で重複が削除される理由 この2点がよく分かりません。 ヘルプを見る限りHASH_KEYはキーを返すだけのはずですが なぜ勝手に削除できるのでしょうか?
ご教授よろしくお願いいたします。
// 重複行の削除.uws HASHTBL hash = HASH_CASECARE
fp=fopen("test.txt",F_READ) for i=1 to fget(fp,-1) hash[fget(fp,i)]=1 // 1 はダミー next fclose(fp)
fp=fopen("new.txt",F_write) for i=0 to length(hash)-1 fput(fp,hash[i, HASH_KEY]) next fclose(fp)
引用元:http://www.nagomi-jp.net/~liners/p0b.htm
|
No.1489 2015/07/23(Thu) 10:12:30
|
☆ Re: 連想配列を使った重複を削除する仕組みについて / stuncloud |
|
|
text.txtの内容が以下だったとして
foo bar foo baz
先ずはじめのforループ内で以下の動作が行われます
hash["foo"] = 1 // foo というキーで値に1を代入 hash["bar"] = 1 // bar というキーで値に1を代入 hash["foo"] = 1 // foo というキーは既に存在するので1を再代入 ※ hash["baz"] = 1 // baz というキーで値に1を代入
ポイントは ※ の部分です 連想配列はキーが存在しなければキーと値のペアが新しく作られ、キーが既に存在していれば値を新たに代入します ここで、hashにはfoo、bar、bazのキーを持つ3つの要素が追加されたことになります これが重複を排除するための仕組みです
> hash[fget(fp,i)]=1 でダミーの数字を指定する理由
上記を踏まえるとわかると思いますが、テキストから読みだした各行を連想配列のキーに入れるのが目的なので値はなんでも良いのです hash[fget(fp,i)] = hash[fget(fp,i)] + 1 例えばこんな風にしておけば、元のテキスト内でその内容の行が幾つあったかをカウントするといった工夫も可能です
> fput(fp,hash[i, HASH_KEY]) で重複が削除される理由
重複の削除は最初のループで終わっているのでここはその結果を書き出しているだけです 読みだした行は連想配列のキーに入れていたので、そのままキーを書き出しています
|
No.1490 2015/07/23(Thu) 11:44:57
|
|
☆ Re: 連想配列を使った重複を削除する仕組みについて / koujichiu |
|
|
じぶんの勉強も兼ねまして、 UWSCのプログラムについているヘルプを使わせてもらって そのまま実験してみました ^^;
その実験結果から解ったというか想像した感じですが、
●ダミーの数字を指定する理由: 配列を初期化するのに要素を入れないとなので、適当に入れてある
(for のループで回してるので要素に 0から要素数-1 の数字をいれてもよいが 面倒なので同じ値を要素に入れている)
●重複が削除される理由: 削除しているというよりも、 連想配列のキーとして使われている、16進数値の文字列が重複しているものを削除し、 これを逆ハッシュして文字列に変換後にソートして並べ直して表示している ような感じかもです
●構想?としては、
1: 連想配列としてのHASHTBL型のキーの値に、各行の文字列を使っている
2: HASHTBLの宣言時に、HASHTBL型のプロパティとして HASH_SORTがデフォルトでtrue になっているのかもで、 すぐ並べ替えられるようになっている (HASH_SORTで、キーに使ってあるハッシュ値の重複部分がわかりつつソートもできる)
3: これは想像ですが、forのループでまわしている時に使っているループ変数iは 連想配列hashのキー文字列ではなく、hashの配列としてのキー番号にひもづけされている のかもで、全部の要素を同じ値にしてもループのなかで個別に全部ヒットする
のかもしれません ^^;
///////////////////////////////////////////////////////////////////////////////
// 連想配列の操作 //PUBLIC HASHTBL B // パブリック、大・小文字区別しない、キーは書込み順 HASHTBL A = HASH_CASECARE or HASH_SORT // 大・小文字区別、キーはソート
A["あ"] = 1 A["う"] = 3 A["お"] = 5 A["え"] = 4 A["い"] = 2 A["お"] = 9
// "う"の値は何? print "'う' の値は " + A["う"]
// "え"があれば削除 ifb A["え", HASH_EXISTS] flg = A["え", HASH_REMOVE] // 必要無くとも変数で受ける endif
print print "// ソート順で表示 (文字型での昇順ソート)" for n = 0 to Length(A)-1 print A[n, HASH_KEY] + " = " + A[n, HASH_VAL] next
A["あ"] = 1 A["う"] = 1 A["お"] = 1 A["い"] = 1 A["お"] = 1
print print "// ソート順で表示 (ただし、値を全部1にしたとき)" for n = 0 to Length(A)-1 print A[n, HASH_KEY] + " = " + A[n, HASH_VAL] next
print print "// ソート順で表示 (ただし、要素の値を一度だけ指定)" print A[1, HASH_KEY] + " = " + A[1, HASH_VAL]
A["あ"] = "" A["う"] = "" A["お"] = "" A["い"] = "" A["お"] = ""
print print "// ソート順で表示 (ただし、値が全部無いとき)" for n = 0 to Length(A)-1 print A[n, HASH_KEY] + " = " + A[n, HASH_VAL] next
////////////////////////////////////////////////////
// 重複行の削除.uws HASHTBL hash = HASH_CASECARE // ●HASH_SORT はデフォでTrue ?
fp=fopen("test.txt",F_READ) for i=1 to fget(fp,-1) //hash[fget(fp,i)]=1 // 1 はダミー hash[fget(fp,i)]="" // ●"" はダミー next fclose(fp)
fp=fopen("new.txt",F_write) for i=0 to length(hash)-1 fput(fp,hash[i, HASH_KEY]) next fclose(fp)
|
No.1491 2015/07/23(Thu) 11:59:52
|
|
☆ Re: 連想配列を使った重複を削除する仕組みについて / koujichiu |
|
|
> stuncloud さん
>キーが既に存在していれば値を新たに代入します
再登録をすることで重複を防ぐ。。。なるほどです
× 16進数値の文字列が重複しているものを削除し、 × × (HASH_SORTで、キーに使ってあるハッシュ値の重複部分がわかりつつソートもできる) ×
////////////////////////////////////////////////////////
あともうひとつ。。。
HASHTBLのプロパティでHASH_SORTがデフォルトでTrueになっていたら、 テキストの重複行削除以外に テキストを並べ替えてしまいますね。。。 m(_ _)m
|
No.1492 2015/07/23(Thu) 12:20:41
|
|
☆ Re: 連想配列を使った重複を削除する仕組みについて / タスク |
|
|
詳しいご解説ありがとうございます! 値が上書きされていたのですね。 盲点でした。 上書きするためにダミーを使うのですね。
お手数おかけしました。
詳しいご説明感謝いたします。 ありがとうございます。
>hash[fget(fp,i)] = hash[fget(fp,i)] + 1
応用を教えていただきありがとうございます。 HASH_valで確認したところ確かにカウントされていました。
今までこういったカウントは ifb文使ってカウントしてたりしてましたが これでコードが省略出来て大変助かります!
hash["foo"] = hash["foo"]+1 hash["bar"] = hash["bar"]+1 hash["foo"] = hash["foo"]+1 hash["baz"] = hash["baz"]+1
こういう状態になってるということですよね。 正直、初めは意味が分からなかったのですが 何度も見返してようやく意味が分かりました。 積極的に使って慣れていこうと思います。
fget(fp,-1)でループかけたり 慣れてる方は凄いですね。。 stuncloudさんありがとうございました!
|
No.1493 2015/07/23(Thu) 12:27:44
|
|
☆ Re: 連想配列を使った重複を削除する仕組みについて / stuncloud |
|
|
> こういう状態になってるということですよね。 そうです > fget(fp,-1)でループかけたり この「-1」は「F_LINECOUNT」定数のことですね、ファイルの行数が得られるので今回のように一行ずつforで処理したい場合にぴったりです
|
No.1494 2015/07/23(Thu) 14:02:08
|
|
☆ Re: 連想配列を使った重複を削除する仕組みについて / タスク |
|
|
koujichiuさん
ヘルプからそこまで推測できるのが凄いです・・・
私は推測すら出来ませんでした。。 これからも掲示版を覗いて勉強させていただきます。
ご回答ありがとうございました。
|
No.1495 2015/07/23(Thu) 17:49:12
|
|
☆ Re: 連想配列を使った重複を削除する仕組みについて / stuncloud |
|
|
せっかくなのでもうひとつ 書き出し部分のforループの代わりにfor inを使うとよりすっきり書けます
for key in hash fput(fp, key) next
連想配列のfor inの場合inの前の変数にはキーが入ります 今回のケースでは不要でしたが、値が欲しい場合は hash[key] とします
|
No.1496 2015/07/23(Thu) 23:47:56
|
|
☆ Re: 連想配列を使った重複を削除する仕組みについて / タスク |
|
|
stuncloudさん 確かによりすっきりですね! ありがとうございますm(__)m
|
No.1497 2015/07/25(Sat) 16:37:52
|
|