0

I have a class which contains three values,

public class hitOBject {
    public string v1;
    public float v2;
    public float v3;
}

I dynamically create these objects during runtime which get stored in their own list.

 List<hitOBject> Detected = new List<hitOBject>();

However, when a new object is added to this list, I first need to check if if there is already a list which contains a a duplicate value. For example...

if I have 2 hitObjects

 obj1            obj2 
 v1 = bob        v1 = bob 
 v2 = 1f         v2 = 3f     
 v3 = 2.5f       v3 = 3.5f  

and if I want to check wether V1 already exists in the list is there a method to do this?

I know that if it was a duplicated object I could just do the following code?

if(!Detected.Contains(object))

but as Im looking for a sub value this wont work?

Can anyone point me in the right direction?

1
  • 2
    Use a HashSet, not a List, and override Equals and GetHashCode. Commented Oct 22, 2014 at 19:33

4 Answers 4

1

Override GetHashCode and Equals.If you are going to compare against only a single field/property in your class then specify that field only like:

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);
    }
}

and then you can use:

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");
}

Since List<T>.Contains uses Equals to compare for equality, the override Equals method will return a bool based on comparison of field v1.

If you are going to have unique values in your List then it is better to use HashSet<T> since it will only allow unique values based on GetHashCode and Equals implementation.

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);

In the above code, at the end, your HashSet will only contain a single item and secondObject will not be added to the HashSet.

If you don't want to override GetHashCode and Equals then you can use a LINQ query to determine if an object exists in your list like:

hitOBject secondObject = new hitOBject {v1 = "bob", v2 = 1f, v3 = 2.5f};
if (Detected.Any(r => r.v1 == secondObject.v1))
{
    //Already exists
}

Another option is to leave your class as it is and implement IEqualityComparer<T> like

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);
    }
}

and then you can pass that in your HashSet<T> constructor like:

Also see: General Naming Conventions C# - MSDN

HashSet<hitOBject> Detected = new HashSet<hitOBject>(new hitObjectV1EqualityComparer());

Later adding items

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);

You will end up with a single item in the HashSet.

You can use that Comparer with List<T>.Contains as well like:

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);    
}
Sign up to request clarification or add additional context in comments.

Comments

1
if(!Detected.Any(o1 => o1.v1 == o2.v1 && o1.v2 == o2.v2 && o1.v3 == o2v3))

Please follow C# conventions. Variables (Detected) should be camelCase, classes (hitObject) should be PascalCase

If the list is big (more than 50 elements) consider using HashSet as @Servy suggested

Comments

0

The any function is LINQ and looks for any match; if not any match, then add to the list... is that what you need?

if (!Detected.Any(Function(i) i.V1 = obj2.V1))
    Detected.Add(obj2);

Just add to get LINQ support:

using System.Linq;

Comments

0

Implement the IEquatable<T> interface in your HitObject:

public class HitObject : IEquatable<HitObject>
{
    public string V1;
    public float V2;
    public float V3;

    public bool Equals(HitObject other)
    {
        return this.V1 == other.V1;
    }
}

Then you can use the Contains method thusly:

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);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.