简体   繁体   中英

How to get combinations distinct by some field with LINQ

I need an LINQ query to get all combinations (distinct by name) for the following structure:

var keys = new[]
{
    new { Name = "A", Value = "1" },
    new { Name = "A", Value = "2" },
    new { Name = "B", Value = "3" },
    new { Name = "B", Value = "4" },
    // etc
};

I need to get:

{A1, B3} {A1, B4} {A2, B3} {A2, B4} // etc

where by A1-B4 I mean whole item: { Name = "...", Value = "..." }

Source array can contains not only A and B elements. For example if we add item { Name = "C", Value = "5" } output result items should contain 3 elements like {A1, B3, C5} .

Thank you.

Try something like this:

var combinations = from A in keys.Where(k=>k.Name == "A")
                   from B in keys.Where(k=>k.Name == "B")
                   select new {A,B};

If you wanna use Linq, then look at the Join operator and hack your own comparer in it.

Within this comparer, you can match items where both the Key and Value are different.

        //
    // Summary:
    //     Correlates the elements of two sequences based on matching keys. A specified
    //     System.Collections.Generic.IEqualityComparer<T> is used to compare keys.
    //
    // Parameters:
    //   outer:
    //     The first sequence to join.
    //
    //   inner:
    //     The sequence to join to the first sequence.
    //
    //   outerKeySelector:
    //     A function to extract the join key from each element of the first sequence.
    //
    //   innerKeySelector:
    //     A function to extract the join key from each element of the second sequence.
    //
    //   resultSelector:
    //     A function to create a result element from two matching elements.
    //
    //   comparer:
    //     An System.Collections.Generic.IEqualityComparer<T> to hash and compare keys.
    //
    // Type parameters:
    //   TOuter:
    //     The type of the elements of the first sequence.
    //
    //   TInner:
    //     The type of the elements of the second sequence.
    //
    //   TKey:
    //     The type of the keys returned by the key selector functions.
    //
    //   TResult:
    //     The type of the result elements.
    //
    // Returns:
    //     An System.Collections.Generic.IEnumerable<T> that has elements of type TResult
    //     that are obtained by performing an inner join on two sequences.
    //
    // Exceptions:
    //   System.ArgumentNullException:
    //     outer or inner or outerKeySelector or innerKeySelector or resultSelector
    //     is null.
    public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqualityComparer<TKey> comparer);

This will get all combinations including {B3, A1}, etc.

var cobinations = from a in keys
              from b in keys.Where(k => k.Name != a.Name)
              select new{ a, b };

This problem has multiple steps:

  1. Separate a list by "Name" into a list of lists L
  2. Perform a cartesian product of list LxL where the lists are distinct
  3. Perfrom a cartesian product of each pair of lists
  4. Merge all the results.

And here is an implementation:

var NameLists = keys.GroupBy(k => k.Name);

var NameListPairs = from first in NameLists
                    from second in NameLists where first != second
                    select new {first, second};

var Result = from pair in NameListPairs
             from first in pair.first
             from second in pair.second
             select new {first, second};

And there you have it. Notice the general pattern of how to do a cartesian product, where we select form two enumerations at once.

EDIT:

If what you want to do is a cartesian product on all name lists, then use this snippet from Eric Lippert . Once you have this, you can use it like so:

var Result = keys.GroupBy(k => k.Name).CartesianProduct();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM