4

A と B という2 つのqueueがあり、次のアルゴリズムを実行します。

while (queueA.Count > 0)
{
    var elemA = queueA.Peek();
    var elemB = queueB.Peek();
    if (AreSimilar(elemA, elemB))
    {
        Debug.Assert(elemA.SomeProperty == elemB.SomeProperty);
        queueA.Dequeue();
        queueB.Dequeue();
    }
    else
    {
        break;
    }    
}

これはもっと簡潔に書くことができると何かが教えてくれます。Dequeue() は Peek() と同じ要素を返すため、Peek() と Dequeue() を 1 つの操作で組み合わせることができ、if ステートメントを while ステートメントと融合して、明示的な中断を回避することができます。同じ動作を正確に維持する方法がわかりません。つまり、「if」の条件を満たさない限り、要素を削除したくありません。

4

3 に答える 3

4

割り当てを の呼び出しに移動するこのコードを試すことができますAreSimilar

QueueElement elemA, elemB
while (queueA.Count > 0 && AreSimilar(elemA = queueA.Peek(), elemB = queueB.Peek())) {
    Debug.Assert(elemA.SomeProperty == elemB.SomeProperty);
    queueA.Dequeue();
    queueB.Dequeue();
}

これは必ずしも読みやすいとは限らないことに注意してください。実際、あなたのバージョンは読みやすさの点でかなり優れています。私が行う唯一のことは、条件を反転してネストを減らすことですが、他のすべてはそのままにしておきます。

while (queueA.Count > 0)
{
    var elemA = queueA.Peek();
    var elemB = queueB.Peek();
    if (!AreSimilar(elemA, elemB))
    {
        break;
    }
    Debug.Assert(elemA.SomeProperty == elemB.SomeProperty);
    queueA.Dequeue();
    queueB.Dequeue();
}
于 2013-03-22T19:24:37.273 に答える
2

AとBが似ている確率は? 確率が高い場合は、想定される一般的なシナリオで常に実行し、それらが似ていると仮定してそれらをポップ(またはデキュー)し、類似していない場合にそれらを押し戻すことを心配することができます...

于 2013-03-22T19:25:40.130 に答える
1

メソッドを使用してループを単純化することはできますが、次のようなごまかしを考えることができます。

static bool DequeuePairIf<T>(
    Func<T, T, bool> predicate,
    Queue<T> queueA,
    Queue<T> queueB)
{
    if (queueA.Count != 0 &&
        queueB.Count != 0 &&
        predicate(queueA.Peek(), queueB.Peek())
    ) {
        queueA.Dequeue();
        queueB.Dequeue();

        return true;
    }

    return false;
}

次に、ループは次のようになります。

while (DequeuePairIf(AreSimilar, queueA, queueB)) { }

しかし、この種のリファクタリングが可読性を向上させるのか、それとも害するのかは疑問です。一つには、元のコードよりもかなり大きいです。一方で、コードが小さいほど読みやすいとは限りません。

(ここでは、ロジックを単純化するためにアサートを削除しました。まだアサートする必要がある場合はPeek()、元のコードで行っているように、呼び出しの結果を保存する必要があります。)

于 2013-03-22T19:27:04.443 に答える