列表列表的交集
Intersection of List of List
我有一个清单列表,如下所示
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>>();
我想根据 ID 将此列表中的列表相交,解决此问题的最佳方法是什么?
Intersect
将在类型完全相等时起作用,在您的情况下不适用,因为您尚未实现 GetHashCode
和 Equals
方法,这是最好的和完整的方式。
因此,如果您只想采用包含在两个列表中的 elements
,那么以下解决方案将适合您。
假设 list1
和 list2
是 List<FilteredVM>
类型,最简单的方法是这样做:
var intersectByIDs = list1.Where(elem => list2.Any(elem2 => elem2.ID == elem.ID));
这里有一个优化的扩展方法:
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))
但它会很浪费,因为它必须构造多个集合。
如果您是单线解决方案的粉丝,您可以使用这个:
List<FilteredVM> result = groupedExpressionResults.Aggregate((x, y) => x.Where(xi => y.Select(yi => yi.ID).Contains(xi.ID)).ToList());
如果您只想要 ID,只需添加 .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);
我有一个清单列表,如下所示
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>>();
我想根据 ID 将此列表中的列表相交,解决此问题的最佳方法是什么?
Intersect
将在类型完全相等时起作用,在您的情况下不适用,因为您尚未实现 GetHashCode
和 Equals
方法,这是最好的和完整的方式。
因此,如果您只想采用包含在两个列表中的 elements
,那么以下解决方案将适合您。
假设 list1
和 list2
是 List<FilteredVM>
类型,最简单的方法是这样做:
var intersectByIDs = list1.Where(elem => list2.Any(elem2 => elem2.ID == elem.ID));
这里有一个优化的扩展方法:
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))
但它会很浪费,因为它必须构造多个集合。
如果您是单线解决方案的粉丝,您可以使用这个:
List<FilteredVM> result = groupedExpressionResults.Aggregate((x, y) => x.Where(xi => y.Select(yi => yi.ID).Contains(xi.ID)).ToList());
如果您只想要 ID,只需添加 .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);