user3292642
user3292642

Reputation: 761

Get all Combination of items

I'm stuck with a combination problem. What I got is a Data class which basically holds a name and a list of values:

public abstract class DataField : IDataField
{        
    public string Name { get; set; }           
    public List<string> Values { get; set; }    
}

At runtime what I'm trying to do is to get every possible combination of a List<DataField> object. What i tried so far is:

// Get dataFields with values
List<IDataField> propertyDataFields = mDataFields.Where(x => x.Values.Count > 0).ToList();

var props = GetPropertiesList(propertyDataFields, 0, propertyDataFields.Count - 1,  new List<List<FieldProperties>>());

private static List<List<FieldProperties>> GetPropertiesList(List<IDataField> propertyDataFields, int listPosition, int position, List<List<FieldProperties>> fieldPropertiesList)
{
    var fieldProperties = new List<FieldProperties>();

    foreach (var item in propertyDataFields[position].Values)
    {
        if (position == -1)
        {
            GetPropertiesList(propertyDataFields, listPosition + 1, propertyDataFields.Count - 1, fieldPropertiesList);
        }
        fieldProperties.Add(new FieldProperties(propertyDataFields[position].Name, item));

        GetProperties(propertyDataFields, position - 1, fieldProperties, fieldPropertiesList);
    }

    return fieldPropertiesList;
}

private static void GetProperties(List<IDataField> propertyDataFields, int position, List<FieldProperties> fieldProperties, List<List<FieldProperties>> fieldPropertiesList)
{
    if (position == -1)
    {
        fieldPropertiesList.Add(fieldProperties);
    }
    foreach (var item in propertyDataFields[position].Values)
    {
        fieldProperties.Add(new FieldProperties(propertyDataFields[position].Name, item));
        GetProperties(propertyDataFields, position - 1, fieldProperties, fieldPropertiesList);
    }
}

At the end i need a List of Lists of FieldProperties objects. The idea was to start with the last dataField in list and loop through all other using a foreach everytime, but this won't work if the first list got only 1 entry for example. Maybe sorting by Values. Count is an idea?

Edit: FieldProperties is a class from another dll im using. I need to create an instance for every DataField.Value.

The szenario is: I got a List<IDataField> e.g.

  var dataFieldAuthor = new DataField() {
  Name = "Author"
  Values = new List<string> { "Author1", "Author2", "Author3" };
  }

and i want to create a List<List<FieldProperties>> with all possible combinations of DataField values.

Upvotes: 0

Views: 231

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205539

You can use the generic method from my answer to How to iterate lists with different lengths to find all permutations?:

public static class Algorithms
{
    public static IEnumerable<T[]> GenerateCombinations<T>(this IReadOnlyList<IReadOnlyList<T>> input)
    {
        var result = new T[input.Count];
        var indices = new int[input.Count];
        for (int pos = 0, index = 0; ;)
        {
            for (; pos < result.Length; pos++, index = 0)
            {
                indices[pos] = index;
                result[pos] = input[pos][index];
            }
            yield return result;
            do
            {
                if (pos == 0) yield break;
                index = indices[--pos] + 1;
            }
            while (index >= input[pos].Count);
        }
    }
}

combined with simple LINQ:

var fields = mDataFields.Where(x => x.Values.Count > 0).ToList();
var result = fields
    .Select(df => df.Values).ToList()
    .GenerateCombinations()
    .Select(c => c.Select((v, i) => new FieldProperties(fields[i].Name, v)).ToList())
    .ToList();

Upvotes: 1

Related Questions