Вот что я собрал:
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
для общности.
person
Tim Sylvester
schedule
25.06.2018