2011-05-20 134 views
1

我有一個IEnumerable(IEnumerable [])的數組,並且想要生成這些IEnumerables中元素的所有可能組合。 它類似於這個問題:Generating Permutations using LINQ 但我不知道預先有多少IEnumerables,因此不能使用描述的LINQ語句。在LINQ中爲n組生成排列

舉個例子: 我的陣列

IEnumerable[] array; 

例如具有這些元素

array[0]={0,1,2}; 
array[1]={a,b}; 

然後我想這些退貨:

{{0,a},{0,b},{1,a},{1,b},{2,a},{2,b}} 

但它可能也可容納:

array[0]={0,1,2}; 
array[1]={a,b}; 
array[2]={w,x,y,z}; 

然後,我會需要適當的排列。我沒有關於多少個IEnumerables的信息,也沒有關於每個IEnumerable擁有多少元素的信息。

在此先感謝您的幫助,

拉爾斯

+0

當你的輸入是數組[0] = {0,1,2}時,你會期望輸出是什麼?陣列[1] = {A,B};陣列[2] = {W,X,Y,Z}? – 2011-05-20 15:40:31

+0

如上所述,我不知道預期的輸出是否真的被視爲所有排列。你有一個假設的約束,每個結果項只有兩個元素? – Yuck 2011-05-20 15:45:54

+0

[生成所有可能的組合]的可能副本(http://stackoverflow.com/questions/3093622/generating-all-possible-combinations) – 2011-05-21 04:10:46

回答

0

似乎你想要Cartesian_product。這應該工作,雖然我沒有特別注意邊緣情況

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); 
     } 
    } 
    } 
} 
+0

儘管如上所述,Eric Lippert在安東尼問題上的解決方案更加漂亮。 – Rob 2011-05-23 15:20:03

+0

感謝羅布,這工作很好!埃裏克的解決方案非常優雅,我同意,但由於我正在使用無類型集合,我無法使用它(或不知道如何)。我的集合中的元素可以是從int到對象的任何東西,儘管每個集合本身都是一致的。 – larsbeck 2011-05-24 06:04:36

0

嘗試以此爲方向(你會需要修改,我敢肯定,我也沒有編譯它,所以有可能是一些語法錯誤)

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; 
} 

同樣,沒有編制,但它應該要做的就是繼續增加「項目1,ITEM2」到了一個列表,其中物品1 =舊「物品1,ITEM2」和ITEM2 =只是來自第n個數組的新條目。因此,字符串數組[a,b,c] +字符串數組[1,2,3,4]應該產生:{a, 1}, {a, 2}, {a, 3}, {a, 4}, {b, 1}...並向第一個字符串數組[x,y,z]添加字符串數組將會產生:{a, 1, x}, {a, 1, y}, {a, 1, z}等等。

+0

謝謝。我沒有嘗試過上面的代碼,因爲它在字符串上運行,Rob的代碼正是我所需要的,但仔細查看它,我認爲我可以輕鬆修改它。 – larsbeck 2011-05-24 06:06:55