C# 如何在集合中查找相似的对象
我希望根据我实现的方法在集合中查找类似对象 例如,此示例类:C# 如何在集合中查找相似的对象,c#,linq,find,C#,Linq,Find,我希望根据我实现的方法在集合中查找类似对象 例如,此示例类: class myObj { public int Data1 { get; set; } public int Data2 { get; set; } public int Data3 { get; set; } } 然后在课堂上实施类似的方法: public bool Similar(myObj obj) { if (obj.Data1 == this.Data1 &&a
class myObj
{
public int Data1 { get; set; }
public int Data2 { get; set; }
public int Data3 { get; set; }
}
然后在课堂上实施类似的方法:
public bool Similar(myObj obj)
{
if (obj.Data1 == this.Data1 && obj.Data2 == this.Data2)
return true;
return false;
}
现在我有了这个收藏:
List<myObj> items = new List<myObj>();
// none similar
items.Add(new myObj() { Data1 = 1, Data2 = 2, Data3 = 4 });
items.Add(new myObj() { Data1 = 2, Data2 = 3, Data3 = 18 });
items.Add(new myObj() { Data1 = 3, Data2 = 4, Data3 = 75 });
items.Add(new myObj() { Data1 = 4, Data2 = 2, Data3 = 3 });
//similar
items.Add(new myObj() { Data1 = 5, Data2 = 26, Data3 = 97 });
items.Add(new myObj() { Data1 = 5, Data2 = 26, Data3 = 37 });
items.Add(new myObj() { Data1 = 10, Data2 = 45, Data3 = 47 });
items.Add(new myObj() { Data1 = 10, Data2 = 45, Data3 = 19 });
List items=newlist();
//不相似
添加(新的myObj(){Data1=1,Data2=2,Data3=4});
添加(新的myObj(){Data1=2,Data2=3,Data3=18});
添加(新的myObj(){Data1=3,Data2=4,Data3=75});
添加(新的myObj(){Data1=4,Data2=2,Data3=3});
//相似的
添加(新的myObj(){Data1=5,Data2=26,Data3=97});
添加(新的myObj(){Data1=5,Data2=26,Data3=37});
添加(新的myObj(){Data1=10,Data2=45,Data3=47});
添加(新的myObj(){Data1=10,Data2=45,Data3=19});
为了获得类似的对象,我做了以下操作:
private static List<myObj> GetSimilars(List<myObj> items)
{
List<myObj> similars = new List<myObj>();
while (items.Count > 0)
{
var q = (from c in items
where c.Similar(items[0])
select c).ToList();
if (q.Count > 1)
{
similars.AddRange(q);
foreach (var obj in q)
items.Remove(obj);
}
else
items.Remove(items[0]);
}
return similars;
}
private静态列表getsimilar(列表项)
{
列表相似=新列表();
而(items.Count>0)
{
变量q=(从项目中的c开始)
其中c.类似(项目[0])
选择c.ToList();
如果(q.计数>1)
{
相似性。AddRange(q);
foreach(q中的var obj)
项目。移除(obj);
}
其他的
项目。删除(项目[0]);
}
返回相似项;
}
有更好的方法吗?使用groupBy进行此操作,您可以根据项目的第一个和第二个值对项目进行分组,如下所示
var GroupByValues=items.GroupBy(obj=> new { val1 = obj.Data1,val2=obj.Data2 });
然后,您可以遍历组以获取值…尝试以下操作:
private static List<myObj> GetSimilars(List<myObj> items)
{
return items.SelectMany(x => items.Where(z => x != z && x.Similar(z))).ToList();
}
private静态列表getsimilar(列表项)
{
return items.SelectMany(x=>items.Where(z=>x!=z&&x.simular(z)).ToList();
}
或者,如果您喜欢:
private static List<myObj> GetSimilars(List<myObj> items)
{
var result = from x in items
from y in items
where x != y && x.Similar(y)
select x;
return result.ToList();
}
private静态列表getsimilar(列表项)
{
var结果=项目中的x
从y到项目
其中x!=y&&x.相似(y)
选择x;
返回result.ToList();
}
您可以使用Linq的GroupBy
和SelectMany来完成这一切:
var similarGroups = from i in items
group i by new { i.Data1, i.Data2 } into D1D2Group
where D1D2Group.Count() > 1
select D1D2Group;
foreach (var grp in similarGroups)
Console.WriteLine("DataGroup:{0}/{1} Count:{2}"
, grp.Key.Data1
, grp.Key.Data2
, grp.Count());
如果要将组展平到列表
,如获取相似项
:
List <myObj> similars = similarGroups.SelectMany(g => g).ToList();
List similar=similarGroups.SelectMany(g=>g.ToList();
您可以实现接口IComparable或使用自行编写的比较器,后者实现IComparaler。若这样做,可以对对象的任意列表进行排序
以下是一个小教程:
要解释示例中调用GetSimilar时修改项目列表的副作用,您必须这样做。要消除副作用,请松开RemoveAll()
private静态列表getsimilar(列表项)
{
var similars=来自项目中的s
其中items.Any(s2=>s!=s2&&s.simular(s2))
选择s;
items.RemoveAll(s=>similars.Contains(s));
返回similar.ToList();
}
制作这个可重用的类怎么样
public class MyObjSimilarity : EqualityComparer<myObj>
{
public override bool Equals(myObj a, myObj b)
{
if (obj.Data1 == this.Data1 && obj.Data2 == this.Data2)
{
return true;
}
return false;
}
public override int GetHashCode(myObj o)
{
int hash = 17;
hash = hash * 23 + o.Data1.GetHashCode();
hash = hash * 23 + o.Data2.GetHashCode();
return hash;
}
}
或者传递到字典的构造函数中
var similarity = new MyObjSimilarity();
var lookup = new Dictionary<myObj, string>(similarity);
或者像另一个答案一样
var similarity = new MyObjSimilarity();
items.GroupBy(
o => o,
o => new { Instance = o, Count = Count(o) },
similarity);
或者在其他对框架友好的地方。看起来您想要声明自己的IEqualityComparer
,您可以在众多linq重载中使用它,我不能使用equals。我已经在其他地方使用它了。我不是说重写等于
,我是说在某个类上实现一个IEqualityComparer
。你试过这个代码吗?因为它不起作用。它有语法错误。测试它并在LinqPad上工作。。。发布语法错误,我将更正它。“'Key.myObj'不包含'Count'的定义,并且找不到接受'Key.myObj'类型的第一个参数的扩展方法'Count'。顺便问一下,什么是密钥?我认为密钥是您的名称空间。。。请使用我的原始代码验证您。。。在我看来,这就像您将Count()-方法放在对象auf myObj中一样,请确保您的查询使用我刚才复制和粘贴的Count()来访问集合。我什么也没变。无论如何,我会检查它。酷答案!!但是如果我想让他们分组呢。比如“Tim Schmelter”的回答?我并不是说我从一开始就想要它,但当我看到它时,我认为这可能会更好。@Star,GroupBy
有很多重载,我添加了一个例子。另一个问题:我可以在外部实现“Equals”吗?我的意思是,如果我更改了类型并想要相同的东西。@当然是Star,但一个公共基类型必须公开类似的属性。@Star,我不确定上一个group by的语法,但你明白了。这显然是可行的。
var similarity = new MyObjSimilarity();
items.Where(o => similarity.Equals(o, w));
var similarity = new MyObjSimilarity();
var lookup = new Dictionary<myObj, string>(similarity);
var similarity = new MyObjSimilarity();
items.GroupBy(o => o, o => o, similarity);
var similarity = new MyObjSimilarity();
items.GroupBy(
o => o,
o => new { Instance = o, Count = Count(o) },
similarity);