Generating Permutations for n sets in LINQ
I have an array of IEnumerable (IEnumerable[]) and would like to generate all possible combinations of the elements in these IEnumerables. It is similar to this problem: Generating Permutations using LINQ but I do not know how many IEnumerables I will have beforehand and thus cannot use the described LINQ statement.
To give an example: My array
IEnumerable[] array;
has for example these elements
array[0]={0,1,2};
array[1]={a,b};
Then I would like these to be returned:
{{0,a},{0,b},{1,a},{1,b},{2,a},{2,b}}
But it might also hold:
array[0]={0,1,2};
array[1]={a,b};
array[2]={w,x,y,z};
Then I would need the appropriate permutations. I do not have any information on how many IEnumerables and no information on how many elements each IEnumerable holds.
Thanks in开发者_如何学Go advance for any help,
Lars
Seems like you want the Cartesian_product. This should work, although I didn't look particularly carefully at edge-cases
public static IEnumerable<T> Drop<T>(IEnumerable<T> list, long numToDrop)
{
if (numToDrop < 0) { throw new ArgumentException("Number to drop must be non-negative"); }
long dropped = 0;
var iter = list.GetEnumerator();
while (dropped < numToDrop && iter.MoveNext()) { dropped++; }
while (iter.MoveNext()) { yield return iter.Current; }
}
public static IEnumerable Concat(object head, IEnumerable list)
{
yield return head;
foreach (var x in list) { yield return x; }
}
public static IEnumerable<IEnumerable> CrossProduct(IEnumerable<IEnumerable> lists)
{
if (lists == null || lists.FirstOrDefault() == null) { yield break; }
var heads = lists.First();
var tails = CrossProduct(Drop(lists, 1));
if (tails.FirstOrDefault() == null)
{
foreach (var h in heads) { yield return new object[] { h }; }
}
else
{
foreach (var head in heads)
{
foreach (var tail in tails)
{
yield return Concat(head, tail);
}
}
}
}
Try this as a direction (you'll need to modify, I'm sure, and I haven't compiled it, so there may be some syntax errors)
public IEnumerable<string> CompileCominations
(IEnumberable<string[]> arrays, List<string> combinations)
{
if(combinations == null) combinations = new List<string>();
for(int i = arrays.Count() - 1; i >= 0; i--)
{
if(combinations.Count >= 1) combinations =
Combine2Lists(combinations, arrays[i]);
else
{
combinations = Combine2Lists(arrays[i], arrays[i -1];
i--;
}
}
return combinations;
}
private List<string> Combine2Lists
(IEnumberable<string> list1, IEnumerable<string> list2)
{
List<string> currentList = new List<string>();
for(int i = 0; i < list1.Count(); i ++)
{
for(int j = 0; j < list2.Count(); j++)
{
currentList.Add(
string.Format("{0},{1}", list1[i], list2[j]);
}
}
return currentList;
}
Again, not compiled, but what it should do is keep adding "item1, item2" to a list with a where item1 = the old "item1, item2" and item2 = just the new entry from the nth array.
Thus string array [a, b, c] + string array [1, 2, 3, 4] should yield: {a, 1}, {a, 2}, {a, 3}, {a, 4}, {b, 1}...
and adding string array [x, y, z] to the first to would then yield: {a, 1, x}, {a, 1, y}, {a, 1, z}
and so forth.
精彩评论