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 { 开发者_StackOverflowName = "C", Value = "5" }
output result items should contain 3 elements like {A1, B3, C5}
.
Thank you.
This problem has multiple steps:
- Separate a list by "Name" into a list of lists L
- Perform a cartesian product of list LxL where the lists are distinct
- Perfrom a cartesian product of each pair of lists
- 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();
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 };
精彩评论