tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルQueueCollectionsの改良
記事No8336
投稿日: 2008/10/17(Fri) 15:08
投稿者ダンボ
お世話になっております。
LILOな処理を行いたく、その制御にはSystem.Collections.Generic.Queue(Of String)を
使うのが便利と考えました。Enqueue,Dequeue,Containsメソッドでおおむね欲しい機能は
実現できるのですが、唯一下記の処理ができません。
・キューの途中にあるItemをキューの先頭に戻す
キューの途中にあるItemをRemoveできれば先頭へのEnqueueでも良いです。

そのような独自Collectionsを継承で定義することができるのではないかと
思うのですが、私の知識ではできません。ヒントをお願いします。

[ツリー表示へ]
タイトルRe: QueueCollectionsの改良
記事No8338
投稿日: 2008/10/17(Fri) 22:32
投稿者よねKEN
結論から言うとキューの途中の値を削除したいという要件には、
フレームワークに用意されているQueueクラス及びそれを継承したクラスは
適さないと思います。

どのクラスを継承すると楽かはわかりませんが、内部的にはList(Of T)を使って、
Queueクラスが持っているのと同名のメソッドを実装するとともに
コレクションとして実装しておくべきインタフェース(IEnumerableとかその他いろいろ)も実装するのが簡単かなと思います。

Queueクラスを継承しても希望のことを実現できないのは、
Queueクラスのメソッドにはキューの途中のアイテムを削除するメソッドはないからです。
(protected/privateなメンバも含めて)

System.Collections.GenericのQueueのソースは見つからなかったので確認していませんが、
少なくともSystem.CollectionsのQueueクラスでは、内部では配列を循環バッファとして使っており、
原理的に途中の項目を削除できませんので、Generic版のQueueクラスでも同様でしょう。

以下は余談です。
用語の使い方が気になったので細かいですが一応ツッコミ入れておきます。。

> LILOな処理を行いたく、

これはLast In, Last Outの意図ですよね、たぶん。
意味を考えた場合、間違いというわけではないですが、
一般的にはFIFO(First In, First Out)と呼ばれます。
#最初に入ったものが最初に出るでも、最後に入ったものが最後に出るでも、結果は同じですけどね。

> その制御にはSystem.Collections.Generic.Queue(Of String)を
> 使うのが便利と考えました。Enqueue,Dequeue,Containsメソッドでおおむね欲しい機能は
> 実現できるのですが、唯一下記の処理ができません。
> ・キューの途中にあるItemをキューの先頭に戻す
> キューの途中にあるItemをRemoveできれば先頭へのEnqueueでも良いです。

Enqueueでも良いということは実現したいのは"先頭"への追加ではなく
"末尾"への追加ですね。

Queueは待ち行列を表現したものなので、
最初に追加したものを先頭、最後に追加したものを末尾と表現します。

[ツリー表示へ]
タイトルRe^2: QueueCollectionsの改良
記事No8340
投稿日: 2008/10/17(Fri) 23:50
投稿者ダンボ
よねKEN さん、いつも有難うございます。
突っ込みも有難うございます。用語は修正します。

Queueクラス流用ではキューの途中の値を削除は無理ですか。惜しいな。

リソースのキャッシュ機構に使いたいのです。リソースを破棄する代わりに
キューに入れておき、実際に破棄するのはキャッシュ数を超えて
あふれたとき。
LRUで行きたいから、キューの途中にいるリソースは取り返して末尾に戻す
ことができると。それでFIFOならぬLILOって感じです。
メソッド名もRetrieveって決めてたのに。。。

まったく別なキャッシュ管理機構を考えるか、どうしてもQueueクラスに
こだわるなら、Dequeue/Enqueueを繰り返してQueueをひとまわし循環させる
うちにその項目を取り除くってことでも何とかなると思っています。

[ツリー表示へ]
タイトル【解決】: QueueCollectionsの改良
記事No8342
投稿日: 2008/10/18(Sat) 15:02
投稿者ダンボ
> こだわるなら、Dequeue/Enqueueを繰り返してQueueをひとまわし循環させる
> うちにその項目を取り除くってことでも何とかなると思っています。

これでいいですかね?キューの最大個数=キャッシュ数は20〜100位と想定して
いるので負荷もそれほどかからないかと。

Public Class RQueue
    Inherits System.Collections.Generic.Queue(Of String)
    Public Sub Renqueue(ByVal Key As String)
        If MyBase.Contains(Key) Then
            Dim LoopCount As Integer = MyBase.Count
            For i As Integer = 1 To LoopCount
                Dim Item As String = MyBase.Dequeue
                If Not Item = Key Then
                    MyBase.Enqueue(Item)
                End If
            Next i
        End If
        MyBase.Enqueue(Key)
    End Sub
End Class

このクラスだけでキューを管理するのでキュー内に同じKeyは無いという前提です。
LoopCountを別出しにしたのは、キューの長さが変わりうるから(必ず1減る)。

[後日追記]この改良クラス利用で望みのキャッシュ機構はうまく動いているみたいです。
着想が現実化できてとても嬉しいです。こういう喜びがプログラミング熱をさまさないで
いる一因と思います。
Purge処理を忘れていたためキャッシュ上に残ったデータがディスクに反映されずに
終わったことは内緒。

[ツリー表示へ]