【问题标题】:Empty while loop with linq/lamba expression带有 linq/lambda 表达式的空 while 循环
【发布时间】:2009-01-26 20:29:50
【问题描述】:

在我工作的地方,我们仍然使用 .Net 2.0,但我对 3.0/3.5 的东西有点熟悉。我想在 C# 中使用 linq/lambda 表达式进行一些练习,所以我编写了一个简单的数独求解器,使用了很多通用的 List<T> 和 lambda 表达式以及它提供的聚合方法。

在我的求解器中,我在求解器算法的顶部有这个:

private Puzzle RecursiveSolve(Puzzle p, int idx)
{
    // start with simple filter to narrow down recursive paths
    // puzzle is still solved without this line, but it takes at least 20x longer
    while( p.board.Any(cell => cell.FilterPossibles()) );  // while(); <- empty while loop is intentional

您可能会说,这是一个简单的递归算法,但我确实对其进行了一些优化以将运行时间降低到合理的水平(我在 google 上找到的最难的谜题是 3.6 秒)。

要理解sn-p,Puzzle.boardList&lt;Cell&gt;Cell.FilterPossibles() 将每个单元格的可能值与同一行、列和 3x3 框中的其他单元格的值进行比较,看看它是否可以消除任何。如果它下降到一种可能,它会设置单元格的值并返回 true。否则返回false。这样,只要电路板上至少有一个单元在上一次迭代中发生变化(已解决),while 循环就会运行。

我担心的是 while 循环是空的。它相当于一种代码气味,并告诉我我可能遗漏了一些东西。有没有办法可以把它写成一个语句,而不是一个循环?

作为这个项目的结果,我实际上有一大堆问题:(我是否在不知不觉中实现了一些我可以告诉编译器的接口?我的函数选择通常合适吗?我有很多布尔方法来简化表达式:这怎么可能更好?我怎样才能更好地构建它以使用不可变的 Puzzle/Cell 对象?)但这是目前最困扰我的一个。

【问题讨论】:

    标签: .net linq lambda


    【解决方案1】:

    一个空的while循环暗示了一个错误或副作用——在这种情况下,它听起来像是副作用,改变了电路板。

    “类似 LINQ”的东西(但不一定有效 - 它真的取决于)是使拼图产生板的迭代器 - 执行另一个迭代将返回一个 new 板(side-无影响)。

    我对你正在做的事情并不真正“满意”,所以这可能不合适 - 但那将是我的第一行询问。

    除此之外,我可能会考虑以某种方式重写它,以使您确实有副作用更明显 - 但同样,在不知道您的代码的情况下,很难确切地说出它是如何产生的会工作的。

    【讨论】:

    • 我可以发布整个内容,但大约有 200 行代码:对 StackOverflow 不太友好。
    • 不,我不是在暗示 :)(我怀疑我也没有时间完全理解它。)
    【解决方案2】:

    我并不是真的反对空循环,我在 C++ 中相对经常使用它们——尽管将主体限定为 { },恕我直言,这更清楚。

    但是,我没有得到您的代码,这似乎表明确实存在代码异味,或者至少可以以更清晰的方式进行表述。

    我没有特别理解的是Any 返回一个布尔值一次。这如何与循环联系在一起?这里的副作用并不明显(你修改了p.board 的内容?)……似乎聪明了,不知何故。

    【讨论】:

    • 这正是我要问的原因。 cell.FilterPossbilities() 有可能修改单元格。我想我知道如何可以做得更好:我需要创建一个已经设置单元格的全新板子,而不是更改板子中的单元格?
    • 只是一个想法:有没有一种方法可以创建一个新板,而无需生成/复制其所有内容?我在这里考虑某种混叠。不过,不确定这会是什么样子。
    • 我将不得不再次阅读 Eric Lippert 在他的博客上如何处理不可变队列。我可能会在那里找到一些有用的东西。
    【解决方案3】:

    我认为具有适当名称的提取方法在这里可能有用。它不会消除气味,但您可以将其从 RecursiveSolver 的第一行移开。 (我可以想象阅读它并立即撞到一堵砖墙)。

    像这样有一个简洁的衬里是可以的,但是使用一个命名良好的方法会更好看...

    重命名 FilterPossibles() 可以创造奇迹...这种方法比它说的要多...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-26
      相关资源
      最近更新 更多