Combinaison de liste>
J'ai une liste de ce type List> qui contient ceci
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> {....,....};
Je veux avoir toutes les combinaisons comme ceci
1-0-6
1-1-6
2-0-6
2-1-6
3-0-6
Et ainsi de suite.
Selon vous est-ce possible de résoudre en utilisant Linq?
7 réponses
C'est assez similaire à cette réponse j'ai donné à une autre question:
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();
Pour un nombre variable d'entrées, maintenant avec des génériques ajoutés:
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();
}
Si le nombre de dimensions est fixe, c'est tout simplement SelectMany
:
var qry = from a in A
from b in B
from c in C
select new {A=a,B=b,C=c};
Cependant, si le nombre de dimensions est contrôlé par les données, vous devez utiliser la récursivité:
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));
}
}
}
Que diriez-vous de suivre la façon de générer des combinaisons en utilisant .Méthode 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);
}
Cette Méthode GenerateCombinations(..) {[7] } fait le travail principal de générer des combinaisons. cette méthode est générique et pourrait donc être utilisée pour générer des combinaisons de tout type.
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;
}
Aide à L'affichage..
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();
}
//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");
}
}
Juste pour le plaisir:
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;
}
}";
}
}
}
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;
}
Grande solution de Abhijeet Nagre. Petite amélioration dans le cas où une série est vide ou les séries sont vides.
List<List<T>> generatedCombinations =
collectionOfSeries.Where(l => l.Any())
.Take(1)
.DefaultIfEmpty(new List<T>())
.First()
.Select(i => (new T[]{i}).ToList())
.ToList();