Comment detail

四字熟語パズルの作成 (Nested Flatten)
Squeak Smalltalk で。

四字熟語のデータは、熟語ごとに行を改めた Unicode のテキストファイル(in.txt)で与えられているとします。

#groupBy:having: は、レシーバ(コレクション)に対し、まず第一引数のブロックで指定した条件(キー)にもとづいて要素を括りだした後、各グループについてあらためて第二引数で与えたブロックの条件に合致するかをチェックし、当てはまるものだけを集めて返すメソッドです。

結果として得られた四個の組の要素に重複がないことは組をセットにしてその要素を数えること(quartet asSet size = 4)で、また、右上隅と左下隅の文字が異なることは、最初の熟語の最後の文字と、最後の熟語の最初の文字が一致しないこと(quartet first last ~= quartet last first)でチェックしています。

お題の例と同じデータを使っているはずなのですが、出力件数は 11712 でした。熟語四組の抽出には、1.0 GHz PowerPC (Mac OS X 10.4.10) で 14 秒弱ほどかかりました(ただし、入出力時間は含まず)。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| in yojis yoji firstCharDict pairs bothCharsDict results out timeToRun |

in := FileStream fileNamed: 'in.txt'.
yojis := OrderedCollection new.
[(yoji := in nextLine) notNil] whileTrue: [yojis add: yoji].
in close.

timeToRun := [
    firstCharDict := yojis
        groupBy: [:each | each first]
        having: [:group | group size > 1].

    pairs := OrderedCollection new.
    yojis do: [:first |
        firstCharDict at: first last ifPresent: [:found |
            found do: [:second | pairs add: {first. second}]]].

    bothCharsDict := pairs
        groupBy: [:pair | {pair first first. pair second last}]
        having: [:group | group size > 1].

    results := OrderedCollection new.
    bothCharsDict do: [:val | val combinations: 2 atATimeDo: [:pair |
        | quartet |
        quartet := pair first, pair second.
        (quartet asSet size = 4 and: [quartet first last ~= quartet last first])
            ifTrue: [results add: quartet]]]
] timeToRun.

out := FileStream fileNamed: 'out.txt'.
results do: [:quartet |
    out nextPutAll: quartet first; cr.
    (2 to: 3) do: [:idx |
        out nextPut: (quartet third at: idx).
        out nextPutAll: '  '.
        out nextPut: (quartet second at: idx); cr].
    out nextPutAll: quartet last; cr; cr].
out edit.

^{results size. timeToRun}   "=> #(11712 13835) "
数が食い違う原因はまだ分からないのですが、とりあえずひとつ明らかなバグが見つかったので修正。結果、少し増えて 12109 件でした。多数派の数にちょっと近づいたか?(^_^;)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@@ -8,7 +8,7 @@
 timeToRun := [
     firstCharDict := yojis
         groupBy: [:each | each first]
-        having: [:group | group size > 1].
+        having: [:group | true].

     pairs := OrderedCollection new.
     yojis do: [:first |
@@ -37,4 +37,4 @@
     out nextPutAll: quartet last; cr; cr].
 out edit.

-^{results size. timeToRun}   "=> #(11712 13835) "
+^{results size. timeToRun}   "=> #(12109 13792) "
Unicode の扱いが分かる言語が Python だけだったので にしおさんの結果と差分をとってみたところ、にしおさんのにあって私のになかったのは次の7個でした。

#('一切即一' '一期四相' '一期四相' '相門有相')
#('一場春夢' '夢中説夢' '一切即一' '一場春夢')
#('一念通天' '天下第一' '一切即一' '一切即一')
#('一了百当' '当代第一' '一切即一' '一切即一')
#('一期一会' '会三帰一' '一切即一' '一切即一')
#('一文不知' '知行合一' '一切即一' '一切即一')
#('一読三嘆' '嘆息嗟嘆' '一切即一' '一読三嘆')

とりあえずこれらについては、私のほうではセットを使って重複を外す手続きをしているのでその関係かと思われます。

これと別に、同じ組み合わせでも順序が違うときに省くかどうかという判断も影響しそうです。
ocean さんの Python 版 12118 個と比較したところ、先の 7 個に加えて次の2点が私のでははじかれていました。やはり、4組のうちの重複要素の扱いに起因する違いのようです。

#('一唱三嘆' '嘆息嗟嘆' '一切即一' '一唱三嘆')
#('一切即一' '一炊之夢' '一炊之夢' '夢中説夢')


あと、以下の並びの異なる2セットをそれぞれ区別するかで 12109 と 12107 の差が出ることも分かりました。

#('一切即一' '一読三嘆' '一唱三嘆' '嘆息嗟嘆')
#('一切即一' '一唱三嘆' '一読三嘆' '嘆息嗟嘆')

#('一炊之夢' '夢中説夢' '一切即一' '一場春夢')
#('一場春夢' '夢中説夢' '一切即一' '一炊之夢')

Index

Feed

Other

Link

Pathtraq

loading...