获取不同的列表值
本文关键字:列表 获取 | 更新日期: 2023-09-27 18:36:36
我有一个C#应用程序,我想从项目对象的List
中获取,另一个包含不同对象的列表。
我试过这个
List<Project> model = notre_admin.Get_List_Project_By_Expert(u.Id_user);
if (model != null) model = model.Distinct().ToList();
列表模型仍然包含 4 个相同的对象Project
。
这是什么原因呢?我该如何解决它?
您需要在此处定义"相同"。我猜你的意思是"具有相同的内容",但这不是类的默认定义:默认定义是"是相同的实例"。
如果您希望"相同"表示"具有相同的内容",则有两种选择:
- 编写一个自定义比较器(
IEqualityComparer<Project>
)并将其作为参数提供给Distinct
- 覆盖
Equals
和GetHashCode
Project
还有一些自定义方法,如DistinctBy
,可以在很多地方使用,如果标识可以由单个属性(通常Id
)确定,这将非常有用 - 但是不在BCL中。但例如:
if (model != null) model = model.DistinctBy(x => x.Id).ToList();
例如:
public static IEnumerable<TItem>
DistinctBy<TItem, TValue>(this IEnumerable<TItem> items,
Func<TItem, TValue> selector)
{
var uniques = new HashSet<TValue>();
foreach(var item in items)
{
if(uniques.Add(selector(item))) yield return item;
}
}
var newList =
(
from x in model
select new {Id_user= x.Id_user}
).Distinct();
或者你可以这样写
var list1 = model.DistinctBy(x=> x.Id_user);
你如何定义相同?您应该使用此定义覆盖Project
中的Equals
(如果您覆盖Equals
也覆盖GetHashCode
)。例如:
public class Project
{
public int ProjectID { get; set; }
public override bool Equals(object obj)
{
var p2 = obj as Project;
if (p2 == null) return false;
return this.ProjectID == m2.ProjectID;
}
public override int GetHashCode()
{
return ProjectID;
}
}
否则,您只是在检查引用相等性。
对象的引用不相等。如果您希望能够在整个对象本身而不仅仅是属性上执行此操作,则必须实现IEqualityComparer或IEquatable
检查此示例:您需要使用比较器或覆盖Equals()
class Program
{
static void Main( string[] args )
{
List<Item> items = new List<Item>();
items.Add( new Item( "A" ) );
items.Add( new Item( "A" ) );
items.Add( new Item( "B" ) );
items.Add( new Item( "C" ) );
items = items.Distinct().ToList();
}
}
public class Item
{
string Name { get; set; }
public Item( string name )
{
Name = name;
}
public override bool Equals( object obj )
{
return Name.Equals((obj as Item).Name);
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
这是一个基本上相同的问题的答案,会有所帮助。
解释:
Distinct() 方法检查引用类型的引用相等性。这意味着它正在寻找字面上相同的重复对象,而不是包含相同值的不同对象。
致谢@Rex
使用下面显示的方法之一不是更简单吗:)?您可以按某个键对域对象进行分组,然后选择 FirstOrDefault,如下所示。
更有趣的选择是创建一些 Comparer 适配器,该适配器将您带到域对象并创建 Comparer 可以使用/处理的其他对象开箱即用。基于比较器,可以创建自定义 linq 扩展,如下面的示例所示。希望对:)有所帮助
[TestMethod]
public void CustomDistinctTest()
{
// Generate some sample of domain objects
var listOfDomainObjects = Enumerable
.Range(10, 10)
.SelectMany(x =>
Enumerable
.Range(15, 10)
.Select(y => new SomeClass { SomeText = x.ToString(), SomeInt = x + y }))
.ToList();
var uniqueStringsByUsingGroupBy = listOfDomainObjects
.GroupBy(x => x.SomeText)
.Select(x => x.FirstOrDefault())
.ToList();
var uniqueStringsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeText).ToList();
var uniqueIntsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeInt).ToList();
var uniqueStrings = listOfDomainObjects
.Distinct(new EqualityComparerAdapter<SomeClass, string>(x => x.SomeText))
.OrderBy(x=>x.SomeText)
.ToList();
var uniqueInts = listOfDomainObjects
.Distinct(new EqualityComparerAdapter<SomeClass, int>(x => x.SomeInt))
.OrderBy(x => x.SomeInt)
.ToList();
}
自定义比较器适配器:
public class EqualityComparerAdapter<T, V> : EqualityComparer<T>
where V : IEquatable<V>
{
private Func<T, V> _valueAdapter;
public EqualityComparerAdapter(Func<T, V> valueAdapter)
{
_valueAdapter = valueAdapter;
}
public override bool Equals(T x, T y)
{
return _valueAdapter(x).Equals(_valueAdapter(y));
}
public override int GetHashCode(T obj)
{
return _valueAdapter(obj).GetHashCode();
}
}
自定义 linq 扩展(DistinctBy 扩展方法的定义):
// Embedd this class in some specific custom namespace
public static class DistByExt
{
public static IEnumerable<T> DistinctBy<T,V>(this IEnumerable<T> enumerator,Func<T,V> valueAdapter)
where V : IEquatable<V>
{
return enumerator.Distinct(new EqualityComparerAdapter<T, V>(valueAdapter));
}
}
测试用例中使用的域对象的定义:
public class SomeClass
{
public string SomeText { get; set; }
public int SomeInt { get; set; }
}
List<ViewClReceive> passData = (List<ViewClReceive>)TempData["passData_Select_BankName_List"];
passData = passData?.DistinctBy(b=>b.BankNm).ToList();
它会起作用...