user1018711
user1018711

Reputation:

Create unique doubles and triplets from collection

I have a Collection (List) of items (String). Number of items in this collection will always be between 0 to 9.

I need to create all combinations of pairs and triples from this collection. Position of item in double or triplet does not matter. So {1,2} is equal to {2,1}.

How can i achieve this? Maybe there is some nice way to do this via LINQ?

Upvotes: 6

Views: 1304

Answers (1)

Elian Ebbing
Elian Ebbing

Reputation: 19027

In the code below I generate all unique doubles and triplets using linq. I use the fact that strings have a total ordering.

This generates all doubles:

string[] items = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };

var combinations = 
    from a in items
    from b in items
    where a.CompareTo(b) < 0
    orderby a, b
    select new { A = a, B = b };

foreach(var pair in combinations)
    Console.WriteLine("({0}, {1})", pair.A, pair.B);

This generates all triplets:

string[] items = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };

var combinations = 
    from a in items
    from b in items
    from c in items
    where a.CompareTo(b) < 0 && b.CompareTo(c) < 0
    orderby a, b, c
    select new { A = a, B = b, C = c };

foreach(var triplet in combinations)
    Console.WriteLine("({0}, {1}, {2})", triplet.A, triplet.B, triplet.C);

Update: There is a generic solution to create all unique subsets of a specific length, and still use linq. However, you need a returntype that can contain the subset. I created a simple class LinkedNode, because to me this feels most natural in combination with linq:

void Main()
{
    string[] items = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };

    foreach(var combination in CreateCombinations(items, 5))
        Console.WriteLine("({0})", combination.ToString());
}

private static IEnumerable<LinkedNode> CreateCombinations(string[] items, int length)
{
    if(length == 1)
        return items.Select(item => new LinkedNode { Value = item, Next = null });

    return from a in items 
        from b in CreateCombinations(items, length - 1) 
        where a.CompareTo(b.Value) < 0
        orderby a, b.Value
        select new LinkedNode<T> { Value = a, Next = b };
}

public class LinkedNode
{
    public string Value { get; set; }
    public LinkedNode Next { get; set; }

    public override string ToString()
    {
        return (this.Next == null) ? Value : Value + ", " + Next.ToString();
    }
}

It should be easy to implement IEnumerable<string> on the class LinkedNode, or otherwise convert the LinkedNodes to a List<string> or HashSet<string>. Note that you can remove the line orderby a, b.Value if the order is not important.

Upvotes: 9

Related Questions