Creating Shared List Combinations

I need to create a list from another list that contains any possible combination. Studying possible solutions, I found many interesting approaches, but everyone seems to generate results based on the number of records provided. I need the combinations to increase to the maximum threshold.

i.e. consider the following array

1,2,3,4,5

I need the results to look similar (threshold value 3 in this example)

1
1,2
1,2,3
1,2,4
1,2,5
1,3,4
2,3,5... etc

In fact, the data will be IEnumerable. I used a simple int [] to illustrate the desired results.

+4
source share
3 answers

:

  • , , . IEnumerable .

  • , 1, .

, (.. {1, 1} {1, 2, 1} ). , remaining values GetCombinations.

yield. , . .

public static IEnumerable<IEnumerable<T>> GetCombinations<T>(IEnumerable<T> values, int threshold)
{
    var remaining = values;

    foreach (T value in values)
    {
        yield return value.Yield();

        if (threshold < 2)
        {
            continue;
        }

        remaining = remaining.Skip(1);

        foreach (var combination in GetCombinations(remaining, threshold - 1))
        {
            yield return value.Yield().Concat(combination);
        }
    }
}

public static IEnumerable<T> Yield<T>(this T item)
{
    yield return item;
}

{1, 2, 3, 4, 5} :

1
1, 2
1, 2, 3
1, 2, 4
1, 2, 5
1, 3
1, 3, 4
1, 3, 5
1, 4
1, 4, 5
1, 5
2
2, 3
2, 3, 4
2, 3, 5
2, 4
2, 4, 5
2, 5
3
3, 4
3, 4, 5
3, 5
4
4, 5
5
+4

, (, , ), , :

public static IEnumerable<IEnumerable<T>> Combinations<T>(
    IList<T> source, int count)

, N :

public static IEnumerable<IEnumerable<T>> Combinations<T>(IList<T> source)
{
    return Enumerable.Range(0, source.Count)
            .SelectMany(i => Combinations(source, i));
}
+1

Here is one solution:

public static IEnumerable<T[]> Combinations<T>(IEnumerable<T> items, int threshold)
{
    var comboBuilder = new List<T>();
    foreach (var combo in EnumerateCombos(items, comboBuilder, 0, threshold))
    {
        yield return combo;
    }
}
private static IEnumerable<T[]> EnumerateCombos<T>(IEnumerable<T> items, List<T> currentCombo, 
                                                   int startIndex, int threshold)
{
    if (currentCombo.Count >= threshold) { yield break; }

    for (int i = startIndex; i < items.Count(); i++)
    {
        //Skip past the items we've already gone through in the current combo:
        var item = items.Skip(i).First();

        //Create a new combination with the next available item:
        currentCombo.Add(item);
        yield return currentCombo.ToArray();

        //Repeat the process with the rest of the remaining items:
        foreach (var combo in EnumerateCombos(items, currentCombo, i + 1, threshold))
        {
            yield return combo;
        }

        //Recursion cleanup:
        currentCombo.RemoveAt(currentCombo.Count - 1);
    }
}
+1
source

All Articles