Search Unity

List.Contains() always FALSE?

Discussion in 'Scripting' started by Reizla, Jan 29, 2015.

  1. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    I'm trying to compare 2 lists with each other. One is the main list while the other is a temp list to be inserted into the main list. This insert has only to be done with NEW entries.

    Here's my code:

    foreach(myMainList entry in tempList)
    {
    if(!MyMainList.Contains(new myMainList(entry.myFoundX,entry.myFoundY,entry.myColor)))
    {
    MyMainList.Add(new myMainList(entry.myFoundX,entry.myFoundY,entry.myColor));
    }
    }

    The problem is that each new entry from tempList is copied into MyMainList, even when that entry (simple coordinates & color code - all int value) already exists in the list. What am I doing wrong here, and how can I correct it?
     
  2. Sbizz

    Sbizz

    Joined:
    Oct 2, 2014
    Posts:
    250
    Contains check if the references match. It doesn't check if the members of the item match (except for the real type like integer, string, etc.)

    Code (CSharp):
    1. foreach(myMainList entry in tempList)
    2. {
    3.     if(!MyMainList.Contains(entry))
    4.     {
    5.         MyMainList.Add(entry);
    6.     }
    7. }
     
  3. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    Thanks for the quick reply. But this code still gives the same problem as I already had - it keeps adding the values that are already in MyMainList. This means that the List.Contains() check still gives FALSE :(
     
  4. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    Screw it. If I can't get it to work how it should be, I'll make my own (very short) routine for it:

    Code (csharp):
    1.   bool InList(int tempx, int tempy, int tempc)
    2.    {
    3.      foreach(myBubbleList entry in MyBubbleList)
    4.      {
    5.        if (entry.myFoundX==tempx && entry.myFoundY==tempy && entry.myColor==tempc)
    6.        {
    7.          return true;
    8.        }
    9.      }
    10.      return false;
    11.    }
    At least this is working as I want it to work. Can't be bothered too much about the actual List.Contains() for now. I'll figure it out when I REALLY need a big list to work with ;-)
     
  5. Dameon_

    Dameon_

    Joined:
    Apr 11, 2014
    Posts:
    542
    List.Contains isn't what you wanted, anyway. Because you're checking it for an object you're creating just for the check, it will NEVER contain that object. Checking for a specific object is not the same as checking to see if the list contains an item with specific values.

    Your function is the simplest way to do what you want. Another option would be to use List.Find() with an appropriate lambda expression.

    The failure here isn't the system, it's your understanding of how the method call you're using works. Read the APIs in the future until you're sure you're using the right tool for the job.
     
    angrypenguin likes this.
  6. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    Thanks for explaining. One question though about List.Find() - can I add multiple values (with &&) to check if they're there already?

    Failure indeed is my understanding of the method or OOP in general. I'm an old-school auto-didact linear programmer (started back in '85). I haven't had any education on programming other than a crash course mastering PHP/MySQL for the latter one.

    My main problem is that there's basically not a single book that explains how OOP works. Each and every book I've tried dives into that virtual thing that OOP is and as long as I don't know how it works, I can't master it. Working with Unity and C# I'm learning it bit by bit.
    And the other problem I have is that I need to see working examples how something works. You can explain it in theory till you drop, but there's a chance I might never be able to understand what's being told (and trust me, I'm not dumb :p )
     
  7. Fenyx

    Fenyx

    Joined:
    Aug 9, 2013
    Posts:
    8
    If you look at the documentation for List.Contains it states that it uses the default Equals method for the object

    If you haven't written an Equals method for your class then it will default to checking if they are equal by seeing if they are the exact same instance of the object.

    Example:
    Person p1 = new Person("Frank");
    Person p2 = new Person("Frank");
    Person p3 = p1;

    if(p1.Equals(p2)) // This is false
    { ... }

    if(p1.Equals(p1)) // This is true
    { ... }


    if(p1.Equals(p3) // this is also true
    { ... }


    But let's say you do write Equals for you class:
    public class Person
    {
    <snip>
    public override bool Equals(System.Object obj)
    {
    // If parameter is null return false.
    if (obj == null)
    {
    return false;
    }

    // If parameter cannot be cast to Person return false.
    Person p = obj as Person;
    if ((System.Object)p == null)
    {
    return false;
    }

    // Return true if the fields match:
    return (name == p.name;
    }
    <snip>
    }


    Then;
    Person p1 = new Person("Frank");
    Person p2 = new Person("Frank");
    Person rachel = new Person("Rachel");

    if(p1.Equals(p2)) // This is true
    { ... }

    if(p1.Equals(p1)) // This is true
    { ... }


    if(p1.Equals(rachel)) // this is false

    TL;DR It isn't checking the parameters of your class for equality unless you tell it to.

    Further (and probably more useful reading)
    https://msdn.microsoft.com/en-US/library/ms173147(v=vs.80).aspx

    https://msdn.microsoft.com/en-us/library/ms131190(v=vs.110).aspx

    Edit: Expanded examples
     
  8. Dameon_

    Dameon_

    Joined:
    Apr 11, 2014
    Posts:
    542
    Yup! You can use && and || in lambda expressions. For example:
    List.Find(x => (x.foo == 1) && (x.bar == 20));

    There's lots of websites that explain OOP in a variety of ways. You're just facing a paradigm shift, so it'll probably take a few different explanations before you get it. There's a huge variety of websites that take a lot of different approaches.
     
  9. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Instead of List.Contains, use List.Any... ex:

    Code (csharp):
    1.  
    2. var someVector = new Vector3(1, 2, 3);
    3.  
    4. If(!myVectorList.Any(v => v.x == someVector.x && v.y == someVector.y && v.z == someVector.z)
    5. {
    6.     myVectorList.Add(someVector);
    7. }
    8.  
    Of course, substitute vector, and the list for your objects.
     
  10. Reizla

    Reizla

    Joined:
    Nov 5, 2013
    Posts:
    136
    Thank you all for your help on this topic (I know, 2 months old already). I've been playing around with the List<> a bit more and am now pretty much capable of getting the data out if it that I want. I've already incorporated a 2nd list in my upcoming game that hold the data of special items to be collected/destroyed. With this list I now 'query' data with the following line:
    Code (csharp):
    1. if (MainGameHandler.SpecialBubbleList[MainGameHandler.SpecialBubbleList.IndexOf(new myBubbleList(myPosX, myPosY,32))].myColor)
    I will still have to remove that InList() function I made before though. But for now I will be working on this 2nd list to get it to work in the game as I want.

    Once more - THANK YOU ALL FOR YOUR HELP!