[ACCEPTED]-Words combinations without repetition-words
What you are trying to do is get all the 2 permutations of a collection.
Here is the 1 code snippet:
static void Main(string[] args)
{
var list = new List<string> { "a", "b", "c", "d", "e" };
var result = GetPermutations(list, 3);
foreach (var perm in result)
{
foreach (var c in perm)
{
Console.Write(c + " ");
}
Console.WriteLine();
}
Console.ReadKey();
}
static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> items, int count)
{
int i = 0;
foreach (var item in items)
{
if (count == 1)
yield return new T[] { item };
else
{
foreach (var result in GetPermutations(items.Skip(i + 1), count - 1))
yield return new T[] { item }.Concat(result);
}
++i;
}
}
Outputs:
a b c
a b d
a b e
a c d
a c e
a d e
b c d
b c e
b d e
c d e
Here's what I put together:
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));
}
produces:
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
Note 11 that this is concise but inefficient and 10 should not be used for large sets or inner 9 loops. Notably, the short arrays are re-created 8 multiple times and could be memoized, and 7 the IEnumerable
will be iterated multiple times, which 6 can cause unexpected work if care is not 5 taken.
Also, if the input contains duplicates 4 then the output will as well. Either use 3 .Distinct().ToArray()
first, or use another solution which includes 2 equality checking and, presumably, takes 1 an IEqualityComparer
for generality.
public IActionResult Index()
{
var list = new List<string> { "a", "b", "c", "d", "e" };
List<string> ret = GetAllCombinations(list).OrderBy(_ => _).ToList();
return View();
}
static IEnumerable<string> GetAllCombinations(IEnumerable<string> list)
{
return list.SelectMany((mainItem, mi) => list.Where((otherItem, oi) => mi < oi)
.Select(otherItem => mainItem + otherItem));
}
Ouput ret:
ab
ac
ad
ae
bc
bd
be
cd
ce
de
0
What about a more functional solution
var list = new List<string> { "a", "b", "c", "d", "e" };
GetAllCombinations(list).OrderBy(_ => _).ToList().ForEach(Console.WriteLine);
static IEnumerable<string> GetAllCombinations(IEnumerable<string> list)
{
return list.SelectMany(mainItem => list.Where(otherItem => !otherItem.Equals(mainItem))
.Select(otherItem => mainItem + otherItem));
}
Ouput:
ab
ac
ad
ae
ba
bc
bd
be
ca
cb
cd
ce
da
db
dc
de
ea
eb
ec
ed
0
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.