4

我有两个队列,比如说 A 和 B,我在它们上执行以下算法:

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;
    }    
}

有人告诉我这可以写得更简洁;Peek() 和 Dequeue() 可以组合在一个操作中,因为 Dequeue() 返回与 Peek() 相同的元素,并且 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 回答