Не думаю, что вы можете значительно улучшить этот запрос ... На самом деле он уже довольно эффективен, потому что каждый шаг имеет гораздо меньше возможных комбинаций, чем предыдущий.
То, что вы могли бы легко сделать, это разложить на части некоторый код, чтобы сделать запрос более читабельным. Например, используйте предикат, который проверяет инвариант алгоритма на каждом шаге, и помощник для построения чисел из цифр (вместо «встроенных» умножений и сложений).
Давайте назовем Dn цифрой в позиции N , а Xn
числом, сделанным из D1 ... Dn. На каждом шаге N должны выполняться следующие утверждения:
- Dn не в [D1 ... D (n-1)]
- Xn делится на N
В следующем коде этот инвариант реализован делегатом isValid
:
// Delegate with variable number of arguments
delegate TResult FuncWithParams<TArg, TResult>(params TArg[] args);
void Main()
{
var oneToNine = Enumerable.Range(1, 9).ToArray();
// Creates a number from its digits
FuncWithParams<int, int> makeNumber =
digits => digits.Aggregate(0, (acc, d) => acc * 10 + d);
// Checks the invariant against a sequence of digits
FuncWithParams<int, bool> isValid =
digits => !digits.Take(digits.Length - 1).Contains(digits.Last())
&& makeNumber(digits) % digits.Length == 0;
var query =
from d1 in oneToNine
from d2 in oneToNine
where isValid(d1, d2)
from d3 in oneToNine
where isValid(d1, d2, d3)
from d4 in oneToNine
where isValid(d1, d2, d3, d4)
from d5 in oneToNine
where isValid(d1, d2, d3, d4, d5)
from d6 in oneToNine
where isValid(d1, d2, d3, d4, d5, d6)
from d7 in oneToNine
where isValid(d1, d2, d3, d4, d5, d6, d7)
from d8 in oneToNine
where isValid(d1, d2, d3, d4, d5, d6, d7, d8)
from d9 in oneToNine
where isValid(d1, d2, d3, d4, d5, d6, d7, d8, d9)
select makeNumber(d1, d2, d3, d4, d5, d6, d7, d8, d9);
query.Dump();
}
Все еще довольно большой, но гораздо более читабельный, чем оригинал ...