最も一致率の高いものを表示する(本棚ツールの改修)

昨日は、スクロールバーを用いて閾値を上下に操作してみた。
infoment.hatenablog.com
これを応用して、今回は「最も高い一致率のもの」を表示することに挑戦する。
f:id:Infoment:20181120215425p:plain

昨日は、スクロールバーの値変更イベントで、一致率の高いものを絞り込んだ。
そこで今回も、この仕組みを利用することにした。

  1. まず、100%で絞り込む
  2. 一致するものがあれば、表示する。
  3. 一致するものが無い場合、スクロールバーの値を1つ下げる。
    ※100だったものが、99になる。
  4. スクロールバーの値が変わったので、自分自身を呼び出して(再帰)改めて絞り込みが行われる。

これを繰り返していくと、最も一致率が高いところまで、自動的にスクロールバーが下がっていって止まることになる。

ユーザーフォーム(BookShelfForm)

まず、最後にスクロールバーの値を100にする。

Private Sub TextBox1_Change()
    Dim str1  As String
        str1 = TextBox1.Value
    Dim str2 As String
    Dim i As Long
    Dim j As Long
        j = j + 1
    Dim MatchRatio As Long
        For i = 1 To UBound(Books)
            str2 = Books(i).書籍名称
            MatchRatio = Levenshtein3(str1, str2)
            BookList(i, 1) = str2
            BookList(i, 2) = i
            BookList(i, 3) = MatchRatio
        Next
        ScrollBar1.Enabled = True
        ScrollBar1.Value = 100
End Sub

次いで、昨日のものに下記の4行を加える。

Private Sub ScrollBar1_Change()
    Dim TempList As Variant
    ReDim TempList(1 To UBound(Books), 1 To 3)
    
    Dim i As Long
    Dim j As Long
        j = 1
        For i = 1 To UBound(Books)
            If BookList(i, 3) >= ScrollBar1.Value Then
                TempList(j, 1) = BookList(i, 1)
                TempList(j, 2) = BookList(i, 2)
                TempList(j, 3) = BookList(i, 3)
                j = j + 1
            End If
        Next
        
        ' 今回の追加個所。↓ここから↓
        If j = 1 Then
            ScrollBar1.Value = ScrollBar1.Value - 1
            Exit Sub
        End If
        ' 今回の追加個所。↑ここまで↑
        
        
    Dim SQC As SeaquenceClass
    Set SQC = New SeaquenceClass
        TempList = SQC.SpecialRedim(TempList, j - 1)
        
        ListBox1.Clear
        ListBox1.List = TempList
        MatchRatioLabel = "一致率:" & ScrollBar1.Value & "%"
End Sub

実際に検索してみると、このようになる。
f:id:Infoment:20181120220218g:plain
ハリー・ポッターと賢者の」までを入力すると、最も一致率の高い「ハリー・ポッターと賢者の石」が、一致率92%でヒットした。

これはこれで、成功か?そうとも言い切れない。なぜなら一文字ずつ入力すると、このような挙動になるからだ。
f:id:Infoment:20181120220637g:plain
これは、「ハリー・ポッターと賢者の石」がシリーズ内で最も文字数が少ないため、正しく題名を入力し続ける限り、常に最も一致率が高くなることに起因する。

また、響きだけうろ覚えだと、このようなる。
f:id:Infoment:20181120220908g:plain
音だけで言えば「賢者の石」なのに、文字数等から「秘密の部屋」が候補として挙がってしまった。

結局のところ、この仕組みだけだと、以下の傾向があるようだ。

  • 情報量が少ない内は(例えば「ハ」しか入力されていない)、正しい候補が表示されない。
  • 情報量が増えるにつれて、候補は一時的に増加する。
  • さらに情報が増えると、新ためて絞り込みが行われる。ただし入力が正しくない場合は、最終的に残る候補が正しいとは限らない。

従って一旦入力した後、めぼしいものが無ければスクロールバーで一致率を下げてみる、などの操作が必要かもしれない。
f:id:Infoment:20181120221726g:plain

或いは100%一致するものが無い場合、TOP10を表示するのも良いかもしれない。しかしTOP10が良いのかTOP5が良いのか、何とも言えない。ハリー・ポッターシリーズは全部で10冊あるので、これに特化すれば、TOP10が都合がよい。だが、そのようなチューニングに意味は無いと思われる。

結局のところ一致率で絞り込む場合、誤記などによる候補の除外を避けることはできるが、逆に上記のような現象に対する「折り合い」が必要になる。実用化には、もう一工夫以上が必要だ。

でも、作ってみて面白かったので、これはこれでアリということにしよう。

参考まで。