Вот что я собрал:
static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> CombinationsWithoutRepetition<T>(
this IEnumerable<T> items,
int ofLength)
{
return (ofLength == 1) ?
items.Select(item => new[] { item }) :
items.SelectMany((item, i) => items.Skip(i + 1)
.CombinationsWithoutRepetition(ofLength - 1)
.Select(result => new T[] { item }.Concat(result)));
}
public static IEnumerable<IEnumerable<T>> CombinationsWithoutRepetition<T>(
this IEnumerable<T> items,
int ofLength,
int upToLength)
{
return Enumerable.Range(ofLength, Math.Max(0, upToLength - ofLength + 1))
.SelectMany(len => items.CombinationsWithoutRepetition(ofLength: len));
}
}
...
foreach (var c in new[] {"a","b","c","d"}.CombinationsWithoutRepetition(ofLength: 2, upToLength: 4))
{
Console.WriteLine(string.Join(',', c));
}
производит:
a,b
a,c
a,d
b,c
b,d
c,d
a,b,c
a,b,d
a,c,d
b,c,d
a,b,c,d
Обратите внимание, что это сжато, но неэффективно и должноне должен использоваться для больших наборов или внутренних петель.Примечательно, что короткие массивы восстанавливаются несколько раз и могут быть запомнены, и IEnumerable
будет повторяться несколько раз, что может привести к неожиданной работе, если не принять меры.
Кроме того, если вход содержитдублирует, то вывод будет также.Либо сначала используйте .Distinct().ToArray()
, либо используйте другое решение, которое включает проверку на равенство и, по-видимому, принимает IEqualityComparer
для общности.