26

我有一个这种类型的列表 List> 包含这个

List<int> A = new List<int> {1, 2, 3, 4, 5};
List<int> B = new List<int> {0, 1};
List<int> C = new List<int> {6};
List<int> X = new List<int> {....,....};

我想要这样的所有组合

1-0-6
1-1-6
2-0-6
2-1-6
3-0-6

等等。

根据您的说法,这可以使用 Linq 解决吗?

4

9 回答 9

39

这与我对另一个问题的回答非常相似:

var combinations = from a in A
                   from b in B
                   from c in C
                   orderby a, b, c
                   select new List<int> { a, b, c };

var x = combinations.ToList();

对于可变数量的输入,现在添加了泛型:

var x = AllCombinationsOf(A, B, C);

public static List<List<T>> AllCombinationsOf<T>(params List<T>[] sets)
{
    // need array bounds checking etc for production
    var combinations = new List<List<T>>();

    // prime the data
    foreach (var value in sets[0])
        combinations.Add(new List<T> { value });

    foreach (var set in sets.Skip(1))
        combinations = AddExtraSet(combinations, set);

    return combinations;
}

private static List<List<T>> AddExtraSet<T>
     (List<List<T>> combinations, List<T> set)
{
    var newCombinations = from value in set
                          from combination in combinations
                          select new List<T>(combination) { value };

    return newCombinations.ToList();
}
于 2009-02-13T12:27:20.203 回答
15

如果维数是固定的,这很简单SelectMany

var qry = from a in A
          from b in B
          from c in C
          select new {A=a,B=b,C=c};

但是,如果维数是由数据控制的,则需要使用递归:

static void Main() {
    List<List<int>> outerList = new List<List<int>>
    {   new List<int>(){1, 2, 3, 4, 5},
        new List<int>(){0, 1},
        new List<int>(){6,3},
        new List<int>(){1,3,5}
    };
    int[] result = new int[outerList.Count];
    Recurse(result, 0, outerList);
}
static void Recurse<TList>(int[] selected, int index,
    IEnumerable<TList> remaining) where TList : IEnumerable<int> {
    IEnumerable<int> nextList = remaining.FirstOrDefault();
    if (nextList == null) {
        StringBuilder sb = new StringBuilder();
        foreach (int i in selected) {
            sb.Append(i).Append(',');
        }
        if (sb.Length > 0) sb.Length--;
        Console.WriteLine(sb);
    } else {
        foreach (int i in nextList) {
            selected[index] = i;
            Recurse(selected, index + 1, remaining.Skip(1));
        }
    }
}
于 2009-02-13T12:16:05.083 回答
9

下面如何使用 .Join 方法生成组合?

static void Main()
{
    List<List<int>> collectionOfSeries = new List<List<int>>
                                {   new List<int>(){1, 2, 3, 4, 5},
                                    new List<int>(){0, 1},
                                    new List<int>(){6,3},
                                    new List<int>(){1,3,5}
                                };
    int[] result = new int[collectionOfSeries.Count];

    List<List<int>> combinations = GenerateCombinations(collectionOfSeries);

    Display(combinations); 
}

此方法GenerateCombinations(..)主要工作是生成组合。此方法是通用的,因此可用于生成任何类型的组合。

private static List<List<T>> GenerateCombinations<T>(
                                List<List<T>> collectionOfSeries)
{
    List<List<T>> generatedCombinations = 
        collectionOfSeries.Take(1)
                          .FirstOrDefault()
                          .Select(i => (new T[]{i}).ToList())                          
                          .ToList();

    foreach (List<T> series in collectionOfSeries.Skip(1))
    {
        generatedCombinations = 
            generatedCombinations
                  .Join(series as List<T>,
                        combination => true,
                        i => true,
                        (combination, i) =>
                            {
                                List<T> nextLevelCombination = 
                                    new List<T>(combination);
                                nextLevelCombination.Add(i);
                                return nextLevelCombination;
                            }).ToList();

    }

    return generatedCombinations;
}

显示助手..

private static void Display<T>(List<List<T>> generatedCombinations)
{
    int index = 0;
    foreach (var generatedCombination in generatedCombinations)
    {
        Console.Write("{0}\t:", ++index);
        foreach (var i in generatedCombination)
        {
            Console.Write("{0,3}", i);
        }
        Console.WriteLine();
    }
    Console.ReadKey();
}
于 2011-11-30T17:18:59.197 回答
2
//Done in 2 while loops. No recursion required
#include<stdio.h>
#define MAX 100
typedef struct list
{
  int elements[MAX];
}list;
list n[10];
int number,count[10],temp[10];
void print();
int main()
{
  int i,j,mult=1,mult_count;
  printf("Enter the number of lists - ");
  scanf("%d",&number);
  for(i=0;i<number;i++)
  {
    printf("Enter the number of elements - ");
    scanf("%d",&count[i]);
    for(j=0;i<count[i];j++)
    {
      printf("Enter element %d - "j);
      scanf("%d",&n[i].elements[j]);
    }
  }
  for(i=0;i<number;i++)
  temp[i]=0;
  for(i=0;i<number;i++)
  mult*=count[i];
  printf("%d\n",mult);
  mult_count=0;
  while(1)
  {
    print();
    mult_count++;
    if(mult_count==mult)
    break;
    i=0;
    while(1)
    {
      temp[i]++;
      if(temp[i]==count[i])
      {
        temp[i]=0;
        i++;
      }
      else break;
    }
  }
  return 0;
}
void print()
{
  int i;
  for(i=0;i<number;i++)
  {
    printf("%d\n",n[i].elements[temp[i]]);
    printf("\n");
  }
}
于 2014-06-17T19:16:42.180 回答
1

只是为了好玩:

using CSScriptLibrary;
using System;
using System.Collections.Generic;

namespace LinqStringTest
{
    public class Program
    {
        static void Main(string[] args)
        {

            var lists = new List<List<int>>() {
                new List<int> { 0, 1, 2, 3 },
                new List<int> { 4, 5 },
                new List<int> { 6, 7 },
                new List<int> { 10,11,12 },
            };
            var code = GetCode(lists);
            AsmHelper scriptAsm = new AsmHelper(CSScript.LoadCode(code));

            var result = (IEnumerable<dynamic>)scriptAsm.Invoke("Script.LinqCombine", lists);

            foreach (var item in result)
            {
                Console.WriteLine(item);
            }

            Console.ReadLine();
        }

        private static string GetCode(List<List<int>> listsToCombine)
        {
            var froms = "";
            var selects = "";

            for (int i = 0; i < listsToCombine.Count; i++)
            {
                froms += string.Format("from d{0} in lists[{0}]{1}", i, Environment.NewLine);
                selects += string.Format("D{0} = d{0},", i);
            }

            return @"using System;
              using System.Linq;
              using System.Collections.Generic;
              public class Script
              {
                  public static IEnumerable<dynamic> LinqCombine(List<List<int>> lists)
                  {
                        var x = " + froms + @"
                                select new { " + selects + @" };
                        return x;
                  }
              }";
        }
    }
}
于 2016-08-17T15:23:22.433 回答
1
    public static List<List<string>> CrossProduct(List<List<string>> s)
    {
        if (!s.Any())
            return new List<List<string>>();

        var c1 = s.First();
        var cRest = s.Skip(1).ToList();
        var sss = from v1 in c1
                  from vRest in CrossProduct(cRest)
                  select (new[] { v1 }.Concat(vRest)).ToList();
        var r = sss.ToList();
        return r;
    }
于 2017-09-15T20:56:23.030 回答
1

Abhijeet Nagre 的绝佳解决方案。在某些系列为空或系列为空的情况下的小改进。

List<List<T>> generatedCombinations = 
    collectionOfSeries.Where(l => l.Any())
                      .Take(1)
                      .DefaultIfEmpty(new List<T>())
                      .First()
                      .Select(i => (new T[]{i}).ToList())                          
                      .ToList();
于 2017-12-01T07:51:16.337 回答
0

从输入列表中生成所有组合

var combinations = AllCombinationsOf(A, B, C);

public static IEnumerable<List<T>> AllCombinationsOf<T>(params List<T>[] inputs)
{
    var seed = Enumerable.Repeat(new List<T>(), 1);
    return inputs.Aggregate(seed, CreateCombinations);
}

private static IEnumerable<List<T>> CreateCombinations<T>(IEnumerable<List<T>> oldCombinations, List<T> newValues)
    =>  from value in newValues
        from combination in oldCombinations
        select new List<T>(combination) {value};

@Garry Shutler的这个答案的简化版本。

在线尝试!(测试用例与问题示例一起包含)

于 2020-12-24T21:03:11.367 回答
0

没有 Linq 和递归的解决方案:

private List<List<T>> GetAllCombinations<T>(List<List<T>> source)
{
    List<List<T>> result = new List<List<T>>();

    foreach (var value in source[0])
    {
        result.Add(new List<T> { value });
    }

    for (int i = 1; i < source.Count; i++)
    {
        var resultCount = result.Count;

        for (int j = 1; j < source[i].Count; j++)
        {
            for (var k = 0; k < resultCount; k++)
            {
                result.Add(new List<T>(result[k]));
            }
        }

        var t = (result.Count / source[i].Count);

        for (int j = 0; j < source[i].Count; j++)
        {
            for (int k = 0; k < t; k++)
            {
                result[j * t + k].Add(source[i][j]);
            }
        }
    }

    return result;
}
于 2021-01-04T09:08:11.667 回答