Ну, наверное, это не так, как я бы написал, но:
static IEnumerable<T[]> Permute<T>(this T[] xs, params T[] pre) {
if (xs.Length == 0) yield return pre;
for (int i = 0; i < xs.Length; i++) {
foreach (T[] y in Permute(xs.Take(i).Union(xs.Skip(i+1)).ToArray(), pre.Union(new[] { xs[i] }).ToArray())) {
yield return y;
}
}
}
Re ваш комментарий; Я не полностью ясно понимаю вопрос; если вы имеете в виду "почему это полезно?" - среди прочего, существует целый ряд сценариев «грубой силы», в которых вы хотели бы попробовать разные варианты - например, для небольших задач заказа, таких как коммивояжер (которые недостаточно велики, чтобы требовать более сложного решения), Возможно, вы захотите проверить, лучше ли идти {база, А, В, С, база}, {база, А, С, В, база}, {база, В, А, С, база} и т. д.
Если вы имеете в виду "как бы я использовал этот метод?" - не проверено, но что-то вроде:
int[] values = {1,2,3};
foreach(int[] perm in values.Permute()) {
WriteArray(perm);
}
void WriteArray<T>(T[] values) {
StringBuilder sb = new StringBuilder();
foreach(T value in values) {
sb.Append(value).Append(", ");
}
Console.WriteLine(sb);
}
Если вы имеете в виду "как это работает?" - блоки итераторов (yield return
) сами по себе являются сложным предметом - у Джона есть свободная глава (6) в его книге . Остальная часть кода очень похожа на ваш первоначальный вопрос - просто используйте LINQ, чтобы обеспечить моральный эквивалент +
(для массивов).