#c# #.net #linq
#c# #.net #linq
Вопрос:
Мне нужен запрос LINQ, чтобы получить все комбинации (отличные по имени) для следующей структуры:
var keys = new[]
{
new { Name = "A", Value = "1" },
new { Name = "A", Value = "2" },
new { Name = "B", Value = "3" },
new { Name = "B", Value = "4" },
// etc
};
Мне нужно получить:
{A1, B3} {A1, B4} {A2, B3} {A2, B4} // etc
где под A1-B4 я подразумеваю весь элемент: { Name = "...", Value = "..." }
Исходный массив может содержать не только элементы A и B. Например, если мы добавим элемент, то { Name = "C", Value = "5" }
результат вывода элементов должен содержать 3 элемента типа {A1, B3, C5}
.
Спасибо.
Комментарии:
1. Может быть .. но я думаю, что с LINQ решение должно быть коротким и более элегантным.
Ответ №1:
Эта проблема состоит из нескольких этапов:
- Разделите список по «имени» на список списков L
- Выполните декартово произведение списка LxL, где списки различны
- Выполните декартово произведение каждой пары списков
- Объедините все результаты.
И вот реализация:
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};
И вот оно. Обратите внимание на общую схему того, как выполнить декартово произведение, где мы выбираем форму двух перечислений одновременно.
Редактировать:
Если то, что вы хотите сделать, это декартово произведение во всех списках имен, тогда используйте этот фрагмент от Эрика Липперта. Как только у вас это будет, вы можете использовать это следующим образом:
var Result = keys.GroupBy(k => k.Name).CartesianProduct();
Комментарии:
1. Спасибо, Крис, но я хочу прояснить один момент. Исходный массив может содержать не только элементы A и B. Например, если мы добавим элемент { Name = «C», Value = «4»}. Элементы выходного результата должны содержать 3 элемента типа {A1, B3, C5}.
Ответ №2:
Попробуйте что-то вроде этого:
var combinations = from A in keys.Where(k=>k.Name == "A")
from B in keys.Where(k=>k.Name == "B")
select new {A,B};
Комментарии:
1. Спасибо, Кейтс, но я хочу прояснить один момент. Исходный массив может содержать не только элементы A и B. Например, если мы добавим элемент { Name = «C», Value = «4»}. Элементы выходного результата должны содержать 3 элемента, таких как {A1, B3, C5}.
2. Что ж, вы можете расширить этот запрос по мере необходимости для любого количества известных измерений. В общем случае это становится сложнее. Смотрите мою правку.
Ответ №3:
Если вы хотите использовать Linq, то посмотрите на оператор Join и взломайте в нем свой собственный компаратор.
В этом средстве сравнения вы можете сопоставлять элементы, у которых отличаются и ключ, и значение.
//
// 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);
Ответ №4:
Это приведет ко всем комбинациям, включая {B3, A1} и т.д.
var cobinations = from a in keys
from b in keys.Where(k => k.Name != a.Name)
select new{ a, b };
Комментарии:
1. Спасибо, поп, но я хочу прояснить один момент. Исходный массив может содержать не только элементы A и B. Например, если мы добавим элемент { Name = «C», Value = «4»}. Элементы выходного результата должны содержать 3 элемента, таких как {A1, B3, C5}.