检查对象的 c# 列表是否包含具有相同变量的对象
本文关键字:对象 变量 是否 列表 检查 包含具 | 更新日期: 2023-09-27 18:27:32
我有一个包含三个值的类,
public class hitOBject {
public string v1;
public float v2;
public float v3;
}
我在运行时动态创建这些对象,这些对象存储在它们自己的列表中。
List<hitOBject> Detected = new List<hitOBject>();
但是,当一个新对象添加到此列表中时,我首先需要检查是否已经有一个包含重复值的列表。例如。。。
如果我有 2 个命中对象
obj1 obj2
v1 = bob v1 = bob
v2 = 1f v2 = 3f
v3 = 2.5f v3 = 3.5f
如果我想检查列表中是否已经存在 V1,有没有一种方法可以做到这一点?
我知道如果它是一个重复的对象,我可以做以下代码吗?
if(!Detected.Contains(object))
但是当我正在寻找子值时,这行不通吗?
谁能指出我正确的方向?
覆盖GetHashCode
和Equals
。如果您打算仅与类中的单个字段/属性进行比较,请仅指定该字段,如下所示:
public class hitOBject
{
public string v1;
public float v2;
public float v3;
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return ((hitOBject)obj).v1 == this.v1;
}
public override int GetHashCode()
{
return (v1 != null ? v1.GetHashCode() : 0);
}
}
然后您可以使用:
List<hitOBject> Detected = new List<hitOBject>();
Detected.Add(new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f});
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
if (Detected.Contains(secondObject))
{
Console.WriteLine("Alread Exists");
}
由于List<T>.Contains
使用Equals
来比较相等性,因此覆盖Equals
方法将根据字段v1
的比较返回一个布尔值。
如果要在List
中使用唯一值,则最好使用HashSet<T>
因为它只允许基于GetHashCode
和Equals
实现的唯一值。
HashSet<hitOBject> Detected = new HashSet<hitOBject>();
Detected.Add(new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f});
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
Detected.Add(secondObject);
在上面的代码中,最后,您的HashSet
将只包含一个项目,secondObject
不会添加到HashSet
中。
如果不想重写GetHashCode
和Equals
,则可以使用 LINQ 查询来确定列表中是否存在对象,如下所示:
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
if (Detected.Any(r => r.v1 == secondObject.v1))
{
//Already exists
}
另一种选择是保持类不变并实现类似IEqualityComparer<T>
private sealed class hitObjectV1EqualityComparer : IEqualityComparer<hitOBject>
{
public bool Equals(hitOBject x, hitOBject y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(x, null)) return false;
if (ReferenceEquals(y, null)) return false;
if (x.GetType() != y.GetType()) return false;
return string.Equals(x.v1, y.v1);
}
public int GetHashCode(hitOBject obj)
{
return (obj.v1 != null ? obj.v1.GetHashCode() : 0);
}
}
然后你可以在你的HashSet<T>
构造函数中传递它,如下所示:
另请参阅:常规命名约定 C# - MSDN
HashSet<hitOBject> Detected = new HashSet<hitOBject>(new hitObjectV1EqualityComparer());
稍后添加项目
Detected.Add(new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f});
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
Detected.Add(secondObject);
您最终会在HashSet
中获得单个项目。
您也可以将该比较器与List<T>.Contains
一起使用,例如:
List<hitOBject> Detected = new List<hitOBject>();
var MyEqualityComparer = new hitObjectV1EqualityComparer();
Detected.Add(new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f});
hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
if (Detected.Contains(secondObject, MyEqualityComparer))
{
//Already Exists
}
else
{
Detected.Add(secondObject);
}
if(!Detected.Any(o1 => o1.v1 == o2.v1 && o1.v2 == o2.v2 && o1.v3 == o2v3))
请遵循 C# 约定。变量(已检测(应为 camelCase,类 (hitObject( 应为 PascalCase
如果列表很大(超过 50 个元素(,请考虑按照建议@Servy使用 HashSet
any 函数是 LINQ 并查找任何匹配项;如果不是任何匹配项,则添加到列表中...这就是你需要的吗?
if (!Detected.Any(Function(i) i.V1 = obj2.V1))
Detected.Add(obj2);
只需添加即可获得 LINQ 支持:
using System.Linq;
在HitObject
中实现 IEquatable<T>
接口:
public class HitObject : IEquatable<HitObject>
{
public string V1;
public float V2;
public float V3;
public bool Equals(HitObject other)
{
return this.V1 == other.V1;
}
}
然后你可以这样使用 Contains
方法:
List<HitObject> detected = new List<HitObject>();
detected.Add(new HitObject
{
V1 = "bob",
V2 = 1f,
V3 = 2.5f
});
HitObject something = new HitObject
{
V1 = "bob",
V2 = 3f,
V3 = 3.5f
};
if (!detected.Contains(something))
{
// this line will not be executed
detected.Add(something);
}