Get all combinations of a list, grouped by name

I have the following TestParam list ... This is a parameter list that is used to determine how the request will be executed. In the following case, the expected result must be performed against all combinations of different parameters. Hence a list of lists with CustomerId 33 along with every product ID available in the list ...

List<TestParam> testList = new List<TestParam>();
        testList.Add(new TestParam() { Name = "CustomerId", Value = "33" });
        testList.Add(new TestParam() { Name = "ProductId", Value = "1" });
        testList.Add(new TestParam() { Name = "ProductId", Value = "2" });
        testList.Add(new TestParam() { Name = "ProductId", Value = "3" });
        testList.Add(new TestParam() { Name = "ProductId", Value = "4" });
        testList.Add(new TestParam() { Name = "ProductId", Value = "5" });
        testList.Add(new TestParam() { Name = "ProductId", Value = "6" });
        testList.Add(new TestParam() { Name = "ProductId", Value = "7" });
        testList.Add(new TestParam() { Name = "ProductId", Value = "8" });

      

TestParam is a normal encapsulated parameter class with a name and a value ...

public class TestParam
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }

      

The end result will be a list of lists with CustomerId 33, with all other products. The same result would be obtained if I had different names and values ​​in the TestParam list (above example).

The following code ends with multiple lists depending on the combinations of the list above ...

   // First get a list of distinct unique param collections...
    List<string> distinctParameterNames = new List<string>();
    testList.GroupBy(x => x.Name).ForEach(paramName => {
        distinctParameterNames.Add(paramName.Key);
    });

    // Get counts
    List<int> combinationList = new List<int>();
    foreach (var x in distinctParameterNames) { 
        combinationList.Add(testList.Where(y=>y.Name == x).Count());
    }

    // Will contain 2 lists, one having all combinations of parameters named CustomerId, and another with ProductId combinations...
    List<List<TestParam>> parameterList = new List<List<TestParam>>();
    foreach (var x in distinctParameterNames) {

        // Loop 
        List<TestParam> parameter = new List<TestParam>();
        testList.Where(paramName => paramName.Name == x).ForEach(y =>
        {

            parameter.Add(new TestParam() { Name = y.Name, Value = y.Value });

        });

        parameterList.Add(parameter);

    }

      

This will be the intersection between the list, and the end result will be a list of lists, and each list will have the following combinations ... So the launch will return (in this case):

  • Customer 33, Product ID 1
  • Customer 33, Product ID 2
  • Customer 33, Product ID 3
  • Customer 33, Product ID 4
  • Customer 33, Product ID 5
  • Customer 33, Product ID 6
  • Customer 33, Product ID 7
  • Customer 33, Product ID 8

What would be the most efficient and general way to do this?

+3


source to share


3 answers


The following is the solution I was looking for ...

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

      



Usage (continues with my code snippet of the question itself):

var intersection = AllCombinationsOf(parameterList.ToArray());

      

+1


source


first select the entire list of clients

var customers = from a in testlist where a.name='customerid'
                select a;

var products = from a in testlist where a.name='productid'
                select a;  

      



then loop customers

for(var c in customers)
{
    loop products
     for(var p in products)
     {
        var customerproducts = new CustomerProducts{
            Customer = c.Name +' ' + c.Value
            Product = p.Name + ' ' + p.value
         };

       then add it into a list 
     }
}

      

0


source


The list must be grouped by Name

, then it can be combined several times depending on the number of groups:

        var groups = testList.GroupBy(_ => _.Name);

        IEnumerable<IEnumerable<TestParam>> result = null;

        foreach (var g in groups)
        {
            var current = g.Select(_ => new[] { _ });
            if (result == null)
            {
                result = current;
                continue;
            }

            result = result.Join(current, _ => true, _ => true, (actual, c) => actual.Concat(c));
        }

        // check result
        foreach (var i in result)
        {
            Console.WriteLine(string.Join(", ", i.Select(_ => string.Format("{0}-{1}", _.Name, _.Value))));
        }

      

0


source







All Articles