C# - using List<T>.Find() with custom objects
Asked Answered
A

5

46

I'm trying to use a List<T> with a custom class of mine, and being able to use methods like Contains(), Find(), etc., on the list. I thought I'd just have to overload the operator == but apparently, one way of doing that is to use a delegate method with the Find()...

Note: Right now, I've overloaded the Equals() method to get the Contains() method to work, but I still couldn't get the Find() function to work.

What would be the best way of getting both to work?

I'm using the latest C# /.NET framework version with mono, on linux.

edit: Here's my code

using System;
namespace GuerreDesClans
{
public class Reponse : IEquatable<Reponse>
{
    public Reponse ()
    {
        m_statement = string.Empty;
        m_pointage = 0;
    }

    public Reponse (string statement, int pointage)
    {
        m_pointage = pointage;
        m_statement = statement;
    }


    /*
     * attributs privés
     */

    private string m_statement;
    private int m_pointage;


    /*
     * properties
     */

    public string Statement {
        get { return m_statement; }
        set { m_statement = value; }
    }

    public int Pointage {
        get { return m_pointage; }
        set { m_pointage = value; }
    }

    /*
     * Equatable
     */

    public bool Equals (Reponse other)
    {
        if (this.m_statement == other.m_statement)
            return true;
        else
            return false;
    }
}

}

and how I would like to search my Reponse objects using the find() function...

list.find("statement1"); // would return a Reponse object
Augsburg answered 21/12, 2010 at 1:57 Comment(0)
Z
73

Find() will find the element that matches the predicate that you pass as a parameter, so it is not related to Equals() or the == operator.

var element = myList.Find(e => [some condition on e]);

In this case, I have used a lambda expression as a predicate. You might want to read on this. In the case of Find(), your expression should take an element and return a bool.

In your case, that would be:

var reponse = list.Find(r => r.Statement == "statement1")

And to answer the question in the comments, this is the equivalent in .NET 2.0, before lambda expressions were introduced:

var response = list.Find(delegate (Response r) {
    return r.Statement == "statement1";
});
Zuniga answered 21/12, 2010 at 2:0 Comment(5)
Can you provide a .NET 2.0 example? I'm in Unity3D which is stuck in .net 2.0 landAmbry
Is it ok to think that the returned element will be a reference and that any modifications to it will be reflected on that same element contained in the list?Stereograph
@HugoAllexisCardona If the type of the element is a reference type, then yes. If it is a value type, then no. See msdn.microsoft.com/en-us/library/t63sy5hs.aspx.Zuniga
And how to deal if the element is not found?Lesbos
@OlivierPons If the list contains reference types, Find will return null if the element is not found. If the list contains value types, it will return the default value for that type if the element is not found. In that case, there is no way to know if the element was found or not, unless the default value cannot match the predicate.Zuniga
L
47

You can use find with a Predicate as follows:

list.Find(x => x.Id == IdToFind);

This will return the first object in the list which meets the conditions defined by the predicate (ie in my example I am looking for an object with an ID).

Lethe answered 21/12, 2010 at 2:0 Comment(2)
what's this technique called ?Augsburg
@Pacane: From msdn - All lambda expressions use the lambda operator =>, which is read as "goes to"Lethe
N
8

Previous answers don't account for the fact that you've overloaded the equals operator and are using that to test for the sought element. In that case, your code would look like this:

list.Find(x => x == objectToFind);

Or, if you don't like lambda syntax, and have overriden object.Equals(object) or have implemented IEquatable<T>, you could do this:

list.Find(objectToFind.Equals);
Naughty answered 21/12, 2010 at 15:20 Comment(4)
These statements are both redundant because we already have a reference to objectToFind. The point of Find() is to locate an object we don't have a reference to. It's much easier, more logical and readable to use list.Contains(objectToFind).Lethe
@Greg Sansom: Of course. But the OP specifically said that he has the Contains method working, but also wants to use Find. Since he has overridden Equals to compare m_statement and ignore the value of m_pointage, the Find method would not necessarily return the same instance that is passed to it. The behavior of the Equals override may be questionable, but given that behavior, list.Find(obj.Equals) is not redundant.Naughty
Whats the return value if no item is found?Victual
@Victual learn.microsoft.com/en-us/dotnet/api/… look in the "Returns" section.Naughty
I
0

http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx

        // Find a book by its ID.
        Book result = Books.Find(
        delegate(Book bk)
        {
            return bk.ID == IDtoFind;
        }
        );
        if (result != null)
        {
            DisplayResult(result, "Find by ID: " + IDtoFind);   
        }
        else
        {
            Console.WriteLine("\nNot found: {0}", IDtoFind);
        }
Informality answered 8/2, 2013 at 6:27 Comment(0)
C
0

It's easy, just use list.Find(x => x.name == "stringNameOfObjectToFind");

Cement answered 2/12, 2018 at 19:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.