LINQ 并从对象数组中删除重复项
LINQ and removing duplicates from an array of objects
我正在尝试使用两列对对象数组进行重复数据删除,其中第二列是字典。最好的描述方式是展示一些代码:
class MyClass
{
public int ID;
public Dictionary<int, int> Dict = new Dictionary<int, int>();
}
现在创建一些对象:
List<MyClass> list = new List<MyClass>();
MyClass mc1 = new MyClass();
list.Add(mc1); mc1.ID = 1; mc1.Dict.Add(1, 1);
MyClass mc2 = new MyClass();
list.Add(mc2); mc2.ID = 1; mc2.Dict.Add(1, 1);
MyClass mc3 = new MyClass();
list.Add(mc3); mc3.ID = 1; mc3.Dict.Add(1, 2);
MyClass mc4 = new MyClass();
list.Add(mc4); mc4.ID = 2; mc4.Dict.Add(1, 1);
我想要完成的是通过 ID 和 Dict 来区分。结果应如下所示:
MyClass 对象列表(不漂亮)
1 //MyClass.ID
1,1 //MyClass.Dictionary
1
1,2
2
1,1
请注意,其中一个对象已从原始列表中删除,因为它具有重复的 ID 和 Dict(字典值)。我一直在玩弄替代版本:
var s = from p in list
group p by p.ID into group1
from group2 in
(from p in group1 group p by p.Dict)
group group2 by group1.Key;
但只是运气不好。感谢人们对解决此问题的任何见解。
PS - 我没有更改规则,但我相信 GROUP BY 和 SELECTFIRST 比带有比较器额外代码的 DISTINCT 更干净。表扬任何可以使用 GROUP BY 解决此问题的人。
对于引用类型,您应该添加 equality comparer
以便执行您想要的操作。添加以下 class:
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass left, MyClass right)
{
if (left == null && right == null)
{
return true;
}
if (left == null || right == null)
{
return false;
}
if (left.ID == right.ID)
{
if (left.Dict == null && right.Dict == null)
{
return true;
}
if (left.Dict == null || right.Dict == null)
{
return false;
}
if (left.Dict.Count != right.Dict.Count)
{
return false;
}
foreach(var key in left.Dict.Keys)
{
if(!right.Dict.ContainsKey(key))
return false;
if (left.Dict[key] != right.Dict[key])
return false;
}
return true;
}
else return false;
}
public int GetHashCode(MyClass author)
{
return (author.ID).GetHashCode();
}
}
并在 Distinct
覆盖中使用该比较器:
List<MyClass> list = new List<MyClass>();
MyClass mc1 = new MyClass();
list.Add(mc1); mc1.ID = 1; mc1.Dict.Add(1, 1);
MyClass mc2 = new MyClass();
list.Add(mc2); mc2.ID = 1; mc2.Dict.Add(1, 1);
MyClass mc3 = new MyClass();
list.Add(mc3); mc3.ID = 1; mc3.Dict.Add(1, 2);
MyClass mc4 = new MyClass();
list.Add(mc4); mc4.ID = 2; mc4.Dict.Add(1, 1);
var result = list.Distinct(new MyClassComparer()).ToList();
你应该改进GetHashCode
方法。这将是你的功课:)
下面的可以拍半张吗? :)
var filteredList = list.GroupBy(mc => mc.ID)
.SelectMany(gr => gr.Distinct(new MyClassComparer()))
.ToList();
比较器:
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass a, MyClass b)
{
return a.Dict.Count == b.Dict.Count && !a.Dict.Except(b.Dict).Any();
}
public int GetHashCode(MyClass a)
{
return a.ID;
}
}
我正在尝试使用两列对对象数组进行重复数据删除,其中第二列是字典。最好的描述方式是展示一些代码:
class MyClass
{
public int ID;
public Dictionary<int, int> Dict = new Dictionary<int, int>();
}
现在创建一些对象:
List<MyClass> list = new List<MyClass>();
MyClass mc1 = new MyClass();
list.Add(mc1); mc1.ID = 1; mc1.Dict.Add(1, 1);
MyClass mc2 = new MyClass();
list.Add(mc2); mc2.ID = 1; mc2.Dict.Add(1, 1);
MyClass mc3 = new MyClass();
list.Add(mc3); mc3.ID = 1; mc3.Dict.Add(1, 2);
MyClass mc4 = new MyClass();
list.Add(mc4); mc4.ID = 2; mc4.Dict.Add(1, 1);
我想要完成的是通过 ID 和 Dict 来区分。结果应如下所示:
MyClass 对象列表(不漂亮)
1 //MyClass.ID
1,1 //MyClass.Dictionary
1
1,2
2
1,1
请注意,其中一个对象已从原始列表中删除,因为它具有重复的 ID 和 Dict(字典值)。我一直在玩弄替代版本:
var s = from p in list
group p by p.ID into group1
from group2 in
(from p in group1 group p by p.Dict)
group group2 by group1.Key;
但只是运气不好。感谢人们对解决此问题的任何见解。
PS - 我没有更改规则,但我相信 GROUP BY 和 SELECTFIRST 比带有比较器额外代码的 DISTINCT 更干净。表扬任何可以使用 GROUP BY 解决此问题的人。
对于引用类型,您应该添加 equality comparer
以便执行您想要的操作。添加以下 class:
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass left, MyClass right)
{
if (left == null && right == null)
{
return true;
}
if (left == null || right == null)
{
return false;
}
if (left.ID == right.ID)
{
if (left.Dict == null && right.Dict == null)
{
return true;
}
if (left.Dict == null || right.Dict == null)
{
return false;
}
if (left.Dict.Count != right.Dict.Count)
{
return false;
}
foreach(var key in left.Dict.Keys)
{
if(!right.Dict.ContainsKey(key))
return false;
if (left.Dict[key] != right.Dict[key])
return false;
}
return true;
}
else return false;
}
public int GetHashCode(MyClass author)
{
return (author.ID).GetHashCode();
}
}
并在 Distinct
覆盖中使用该比较器:
List<MyClass> list = new List<MyClass>();
MyClass mc1 = new MyClass();
list.Add(mc1); mc1.ID = 1; mc1.Dict.Add(1, 1);
MyClass mc2 = new MyClass();
list.Add(mc2); mc2.ID = 1; mc2.Dict.Add(1, 1);
MyClass mc3 = new MyClass();
list.Add(mc3); mc3.ID = 1; mc3.Dict.Add(1, 2);
MyClass mc4 = new MyClass();
list.Add(mc4); mc4.ID = 2; mc4.Dict.Add(1, 1);
var result = list.Distinct(new MyClassComparer()).ToList();
你应该改进GetHashCode
方法。这将是你的功课:)
下面的可以拍半张吗? :)
var filteredList = list.GroupBy(mc => mc.ID)
.SelectMany(gr => gr.Distinct(new MyClassComparer()))
.ToList();
比较器:
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass a, MyClass b)
{
return a.Dict.Count == b.Dict.Count && !a.Dict.Except(b.Dict).Any();
}
public int GetHashCode(MyClass a)
{
return a.ID;
}
}