Пустой цикл while с выражением linq / lamba - PullRequest
1 голос
/ 26 января 2009

Там, где я работаю, мы все еще работаем на .Net 2.0, но я немного знаком с материалами 3.0 / 3.5. Я хотел немного попрактиковаться в использовании выражения linq / lambda в C #, поэтому я написал простой решатель судоку, использующий множество обобщенных List<T> и лямбда-выражений с агрегатными методами, которые он предоставляет.

В моем решателе у меня есть это наверху алгоритма решателя:

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

Как вы, вероятно, можете сказать, это простой рекурсивный алгоритм, но я немного его оптимизировал, чтобы сократить время выполнения до чего-то разумного (3,6 с для самой сложной головоломки, которую я мог найти в Google).

Чтобы понять фрагмент, Puzzle.board - это List<Cell>, а Cell.FilterPossibles() проверяет возможные значения каждой ячейки по значениям других ячеек в той же строке, столбце и блоке 3x3, чтобы увидеть, может ли он устранить их. Если он доходит до одного возможного, он устанавливает значение для ячейки и возвращает true. В противном случае возвращается false. Так что цикл while будет работать до тех пор, пока хотя бы одна ячейка на доске изменилась (была решена) в предыдущей итерации.

Что меня беспокоит, так это то, что цикл while пуст. Это похоже на запах кода и говорит мне, что я, вероятно, что-то упустил Есть ли способ, которым я мог бы написать это как утверждение, а не цикл?

В результате этого проекта у меня возникла целая куча вопросов: (Я по незнанию реализовал некоторые интерфейсы, о которых мог бы рассказать компилятору? Являются ли мои варианты выбора подходящими? У меня есть много логических методов для упрощения выражений : как это могло бы быть лучше? Как я мог бы лучше спроектировать это так, чтобы можно было использовать неизменяемые объекты Головоломка / Клетка?) Но это то, что сейчас мучает меня больше всего.

Ответы [ 3 ]

1 голос
/ 26 января 2009

Я на самом деле не против пустых циклов, я использую их относительно часто в C ++ - хотя квалифицирую тело как { }, что намного яснее, ИМХО.

Однако я не получаю ваш код, который, кажется, указывает на то, что действительно есть запах кода или, по крайней мере, что он может быть сформулирован более четко.

В частности, я не понимаю, что Any возвращает единственное логическое значение, один раз . Как это связать вместе с петлей? Побочный эффект здесь действительно неочевиден (вы изменяете содержимое p.board?)… Кажется слишком умным, каким-то образом.

1 голос
/ 27 января 2009

Я думаю, что здесь может быть полезен метод извлечения с соответствующим именем. Это не устранит запах, но вы можете убрать его с самой первой строки в вашем RecursiveSolver. (Я мог вообразить, читая это и поражая кирпичную стену сразу).

Можно иметь такие лайнеры, но это будет выглядеть лучше с хорошо названным методом ...

Переименование FilterPossibles () может творить чудеса ... Этот метод делает больше, чем просто говорит ...

1 голос
/ 26 января 2009

Пустой цикл while предлагает либо ошибку, либо побочные эффекты - в этом случае это звучит как побочные эффекты, меняя доску.

Что было бы "LINQ-подобным" (но не обязательно эффективным - оно действительно зависит) - это заставить головоломку создать итератор досок - выполнение другой итерации вернет новую доску (побочный эффект) -бесплатно).

Я не совсем в курсе того, что вы делаете, так что это может быть неуместно - но это будет моей первой строкой расследования.

Кроме этого, я бы, вероятно, подумал о том, чтобы как-то переписать его, чтобы сделать более очевидным, что у вас есть есть побочные эффекты - но опять же, не зная вашего кода, трудно сказать, как именно это будет работа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...