2015-06-25 1 views
2

У меня есть список списков, который выглядит следующим образомПересечение Списка Списка

public class FilteredVM 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public string Number { get; set; } 
} 

List<List<FilteredVM>> groupedExpressionResults = new List<List<FilteredVM>>(); 

Я хотел бы Intersect списков в этом списке, основанном на идентификаторы, Что лучший способ решить это?

+0

Пересечение, что означает, что вы хотите получить окончательный список, все элементы которого могут быть найдены (по идентификатору) во всех списках входных данных? – adv12

+0

Что бы вы хотели, чтобы результат был? Думаю, я понимаю, что вы хотите «Список '? – Cyral

+0

Я хотел бы получить список идентификаторов, которые находятся во внутренних списках – JohnCooling

ответ

4

Вот оптимизированный метод расширения:

public static HashSet<T> IntersectAll<T>(this IEnumerable<IEnumerable<T>> series, IEqualityComparer<T> equalityComparer = null) 
{ 
    if (series == null) 
     throw new ArgumentNullException("series"); 

    HashSet<T> set = null; 
    foreach (var values in series) 
    { 
     if (set == null) 
      set = new HashSet<T>(values, equalityComparer ?? EqualityComparer<T>.Default); 
     else 
      set.IntersectWith(values); 
    } 

    return set ?? new HashSet<T>(); 
} 

Используйте это со следующим компаратором:

public class FilteredVMComparer : IEqualityComparer<FilteredVM> 
{ 
    public static readonly FilteredVMComparer Instance = new FilteredVMComparer(); 

    private FilteredVMComparer() 
    { 
    } 

    public bool Equals(FilteredVM x, FilteredVM y) 
    { 
     return x.ID == y.ID; 
    } 

    public int GetHashCode(FilteredVM obj) 
    { 
     return obj.ID; 
    } 
} 

Нравится это:

series.IntersectAll(FilteredVMComparer.Instance) 

Вы могли бы просто написать

series.Aggregate((a, b) => a.Intersect(b, FilteredVMComparer.Instance)) 

но полукольцо быть расточительным, потому что должны были бы построить несколько наборов.

+0

Точно, что мне нужно, работает. Спасибо! – JohnCooling

0

Intersect будет работать, если тип мертв, равно, что в вашем случае не будет применяться, потому что вы не внедрили методы GetHashCode и Equals, что является лучшим и полным способом.

Таким образом, если вы только намеревались принять elements, который содержится в обоих списках, то следующее решение вам подойдет.

Предполагая list1 и list2 являются тип List<FilteredVM> чем, самый простой способ, будет делать это:

var intersectByIDs = list1.Where(elem => list2.Any(elem2 => elem2.ID == elem.ID)); 
0

Если вы являетесь поклонником однострочных решений вы можете использовать это:

List<FilteredVM> result = groupedExpressionResults.Aggregate((x, y) => x.Where(xi => y.Select(yi => yi.ID).Contains(xi.ID)).ToList()); 

И если вы просто хотите, идентификаторы вы можете просто добавить .Select(x => x.ID), как это:

var ids = groupedExpressionResults.Aggregate((x, y) => x.Where(xi => y.Select(yi => yi.ID).Contains(xi.ID)).ToList()).Select(x => x.ID); 

Working Demo