我有MyObject with field:id,a,b,c,e,f 并且我有50万个项目列表,现在如何删除所有具有相同参数a,c,f的重复项目?
我正在寻找最快速,最有效的方法。
更新
我实现了比较器
我班级中的字段属于不同类型,因此我使用ToString()
。这是好方法吗?
IdLoc
,IdMet
,Ser
很长?
Value
是对象
IdDataType
很长
class Comparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.IdLoc == y.IdLoc && x.IdMet == y.IdMet && x.Ser == y.Ser &&
x.IdDataType == y.IdDataType && x.Time == y.Time && x.Value == y.Value;
}
public int GetHashCode(MyObject obj)
{
string idLoc = obj.IdLoc.HasValue ? obj.IdLoc.ToString() : String.Empty;
string idMet = obj.IdMet.HasValue ? obj.IdMet.ToString() : String.Empty;
string ser = obj.Ser.HasValue ? obj.Ser.ToString() : String.Empty;
string value = obj.Value != null ? obj.Value.ToString() : String.Empty;
return (idLoc + idMet + ser + value + obj.IdDataType.ToString() + obj.Time.ToString()).GetHashCode();
}
}
删除重复项
元素566 890
1)时间:2秒
DateTime start = DateTime.Now;
List<MyObject> removed = retValTmp.Distinct(new Comparer()).ToList();
double sec = Math.Round((DateTime.Now - start).TotalSeconds, 3);
2)时间:1.5秒
start = DateTime.Now;
List<MyObject> retList = new List<MyObject>();
HashSet<MyObject> removed2 = new HashSet<MyObject>(new Comparer());
foreach (var item in retValTmp)
{
if (!removed2.Contains(item))
{
removed2.Add(item);
retList.Add(item);
}
}
double sec2 = Math.Round((DateTime.Now - start).TotalSeconds, 3);
4)我也尝试过这种方式:
start = DateTime.Now;
var removed3 = retValTmp.Select(myObj => new { myObj.IdLoc, myObj.IdMet, myObj.Ser, myObj.Value, myObj.IdDataType, myObj.Time }).Distinct().ToList();
double sec3 = Math.Round((DateTime.Now - start).TotalSeconds, 3);
时间:0.35秒
但是返回的列表不在我的班级中,为什么1和2列表中的元素数量与3的列表不同?
UPDATE2
public int GetDataHashCode(MyObject obj)
{
long idLoc = obj.IdLoc.HasValue ? obj.IdLoc.Value : 0;
long idMet = obj.IdMet.HasValue ? obj.IdMet.Value : 0;
long ser = obj.SerHasValue ? obj.Ser.Value : 0;
int valueHash = 0;
if (obj.Value != null)
valueHash = obj.Value.GetHashCode();
else
valueHash = valueHash.GetHashCode();
return (idLoc.GetHashCode() + idMet.GetHashCode() + ser.GetHashCode() + valueHash + obj.IdDataType.GetHashCode() + obj.Time.GetHashCode()).GetHashCode();
}
使用:
foreach (MyObject daItem in retValTmp)
{
int key = GetDataHashCode(daItem);
if (!clearDict.ContainsKey(key))
clearDict.Add(key, daItem);
}
元素:750 000
时间: 0.23秒!
答案 0 :(得分:3)
如果您正在寻找的是速度,并且不介意耗尽一些内存,那么我建议您使用HashSet
,如果您有兴趣进行一些自定义比较,那么您可以制作一个IEqualityComparer<T>
,像这样:
var original = new ArrayList(); // whatever your original collection is
var unique = new HasSet<YourClass>(new MyCustomEqualityComparer());
foreach(var item in original)
{
if(!unique.Contains(item))
unique.Add(item);
}
return unique;
这里的问题是你可能最终吞噬原始记忆的两倍。
我做了一些额外的研究,我认为你只需要做到就能实现你想要的东西:
var original // your original data
var unique = new HashSet<YourClass>(origin, new CustomEqualityComparer());
应该注意删除重复数据,因为HashSet
中不允许重复。我建议您同时查看有关GetHasCode
实施指南的this question。
如果您想了解有关HashSet
课程的更多信息,请点击以下链接:
About HashSet
About IEqualityComparer constructor
IEqualityComparer documentation
希望这会有所帮助
答案 1 :(得分:0)
一种有效的方法首先是基于(a,c,f)的散列的快速排序(或类似的n log n排序)然后你可以迭代结果列表,每次选择一个值(a,c,f)的变化。
这将提供一个n log n速度解决方案,这可能是你能做的最好的。
答案 2 :(得分:0)
你总是可以像这样使用LINQ Distinct()
:
var matches = list.Distinct(new Comparer()).ToList();
但是要让Ditsinct()
工作,你需要为你的类实现Comparer:
class Comparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.a == y.a && x.c == y.c && x.f == y.f;
}
public int GetHashCode(MyObject obj)
{
return (obj.a + obj.c + obj.f).GetHashCode();
}
}
答案 3 :(得分:0)
Drakko!
您可以使用Distinct()
方法仅获取指定属性的值不同的值
你可以这样做:
List<MyObj> list = new List<MyObj>();
//Run the code that is going to populate your list.
var result = list.Select(myObj => new { myObj.a, myObj.c, myObj.f})
.Distinct().ToList();
//Result contains the data based on the difference.
答案 4 :(得分:0)
此链接中的代码对我很有用。 https://nishantrana.me/2014/08/14/remove-duplicate-objects-in-list-in-c/
public class MyClass
{
public string ID { get; set; }
public string Value { get; set; }
}
List<MyClass> myList = new List<MyClass>();
var xrmOptionSet = new MyClass();
xrmOptionSet.ID = "1";
xrmOptionSet.Value = "100";
var xrmOptionSet1 = new MyClass();
xrmOptionSet1.ID = "2";
xrmOptionSet1.Value = "200";
var xrmOptionSet2 = new MyClass();
xrmOptionSet2.ID = "1";
xrmOptionSet2.Value = "100";
myList.Add(xrmOptionSet);
myList.Add(xrmOptionSet1);
myList.Add(xrmOptionSet2);
// here we are first grouping the result by label and then picking the first item from each group
var myDistinctList = myList.GroupBy(i => i.ID)
.Select(g => g.First()).ToList();