I have found many solutions giving a collection elements combined in all possible orders but they all use every element just once in every result while I need them to be tr
What you are asking for are permutations not combinations. Unique combinations can be found through tree traversal of k of n elements. If you want n of n elements unique, the answer is 1
Simple - you count. If you have 3 elements, as in your example, and want all two-element combinations, you just count from 0 to 8 (3^2 - 1), and treat the result as a base-3 number with your elements as the digits.
If you have 15 elements and want 8-element combinations, you count from 0 to 15^8-1 and treat your result as a base-15 number.
You can use a depth first search:
class Program
{
private static string[] letters = {"a", "b", "c"};
private static void dfs(string accum, int depth)
{
if (depth == 0)
{
System.Console.WriteLine(accum);
return;
}
foreach (string c in letters)
dfs(accum + c, depth - 1);
}
public static void Main()
{
int depth = 2; //Number of letters in each result
dfs("", depth);
System.Console.ReadLine();
}
}
Output:
aa
ab
ac
ba
bb
bc
ca
cb
cc
Lets say you've got N input elements, and you want a K-long combination.
All you need to do is to count in base N, scoped of course, to all numbers that have K digits.
So, lets say N = {n0, n1, ... nN}
You'd start from the number [n0 n0 ... n0], and count all the way up to [nN nN ... nN]
If you'd like help in understanding how to count in another base, you can get that here
Each number that you compute maps to one of the K-long combinations that you need.
I think an example will help
I'll use your values. N = {a, b, c} So we want to count in base 3. Since we want 2-long combinations, we only care about 2-digit numbers. The smallest 2-digit base 3 number is 00, so we start there. By counting in base 3, we get:
00
01
02
10
11
12
20
21
22
Ok, so now to convert these numbers into a combination.
Remember, our set is {a, b, c}
So whenever we see a 0, it implies 1. Wherever we see 1, it implies 2, and I'm sure you can guess what a 2 implies :)
00 aa
01 ab
02 ac
10 0 => a ba
11 1 => b bb
12 2 => c bc
20 ca
21 cb
22 cc
Eric Lippert has presented a general-purpose method of generating a cartesian product from any number of sequences which he blogs about here.
He wrote an extension method that looks like this:
public static class Combinations
{
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat<T>(new[] { item }));
}
}
Given that extension method, the solution to the original problem can be done like this:
var items = new[] { "a", "b", "c" };
int numInEachSelection = 2;
var combs = Enumerable.Repeat(items, numInEachSelection).CartesianProduct();
foreach (var comb in combs)
Console.WriteLine(string.Join(", ", comb));
Note that combs
is an IEnumerable<IEnumerable<string>>
- it is a sequence of enumerables each of which is a sequence representing one combination.
If you don't need a general-purpose method like that and you are happy to have each combination in a separate object with properties called Item1
and Item2
for the two combined items, the easiest way is this:
var items = new[] { "a", "b", "c" };
var combs = from Item1 in items from Item2 in items select new {Item1, Item2};
foreach (var comb in combs)
Console.WriteLine(comb);