Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

I have an object called Node that has 3 properties. I create a List generic to hold a bunch of these node objects.

 

Then I want to loop over a different collection of nodes and find out if they exist in the first collection mentioned above. How can I go about that? I know there is an IndexOf method on the List object but I think that is to find the same instance of a node (which in my case would never return true).

 

I see that there are Find methods that take predicates but I am not testing to see if the node matches some pattern, I just want to see if my node is in the List collection.

 

I would imagine that i have to override Equals or Compare because I figure there is no way .NET is going to know which of the 3 properties I want to compare. It turns out that I only want to compare one of the props and not all.

 

Any code suggestions?

Wanna-Be C# Superstar
Posted

I beleive that List<T> has a Contains method. I would use that. The trick is to get the Contains method to work for your Node class the exact way you want it to. To get that to work, you need to implement the IEquatable interface in your Node class.

 

The basic gist is that Contains wants to check an Equals method so it requests an EqualityComparer from the object it is checking. For your object to return one, it needs to implement IEquatable. If you don't, your custom object will return a default EqualityComparer which probably won't do what you want it to.

 

And some references for the above stuff I talked about...

http://msdn2.microsoft.com/en-us/library/bhkz42b3.aspx

http://msdn2.microsoft.com/en-us/library/ms224763.aspx

http://msdn2.microsoft.com/en-us/library/ms131187.aspx

Posted

Cool. Va keepin' it real.

 

I am going to try what you suggest but in the meantime I think this is working:

 

  
 public override bool Equals(object obj)
       {
           if (obj == null) return false; //1if the obj passed in is null it can't be equal to anything
           if (Object.ReferenceEquals(this, obj)) return true;//2if the object passed in is the same instance then its equal
           if (this.GetType() != obj.GetType()) return false; //3if the objects aren't the same type they can't be equal
           Node n = obj as Node;
           if (n == null) return false;//if the cast failed it ain't equal this might be the same as 3
           if (nodeID.Equals(n.nodeID)) return true;
           return false;
       }

       public override int GetHashCode()
       {
           return nodeID.GetHashCode();
       }

Wanna-Be C# Superstar
  • Leaders
Posted

Overriding Equals works, and IEquitable works. Predicates can work too.

 

// Create a collection of objects for the example
List<Control> controls = new List<Control>();

public void PrepareExample() {
   // Populate list
   controls.AddRange(new Button[] {new Button(), new Button()});
   // Set one of the objects so that it will match our search criteria.
   controls[1].Name = "ThisIsTheButtonYouWant";
}

public void PredicateExample() {
   // Create an object for the example that defines our search citeria.
   Control CompareAgainst = new Button();
   CompareAgainst.Name = "ThisIsTheButtonYouWant";

   // This is the important code
   Control ControlIFound = controls.Find(
       delegate(Control c)
       {
           return c.Name == CompareAgainst.Name;
       }
   );

   MessageBox.Show(ControlIFound.Name);
}

That looks like a hefty chunk of code to determine whether a list has a certain object or not, but most of that code actually sets up the example. The heart of the code, which is the only code you will actually need to write in your program, is pretty short:

   Control ControlIFound = controls.Find(
       delegate(Control c)
       {
           return c.Name == CompareAgainst.Name;
       }
   );

More or less the same amount of code as would be written to override Equals or implement IEquitable. Like so:

// We will have a variable we want to compare to, for example:
Node checkAgainst;

// Create a bool that indicates whether the list has an equal node.
bool ItemIsInList = null != MyNodeList.Find(
   delegate(Node n) {
       return n == null ? 
           false :
           n.nodeID = checkAgainst.nodeID;
   }
};

Not recommending you fix your code that isn't broken, but it's always nice to have another way to do something, and Predicate<T> methods can do alot more than compare for equality.

[sIGPIC]e[/sIGPIC]
Posted

That's actually a really sweet solution. It's great for one off generic collections that you can create on the fly and avoid all the overhead normally associated with creating a strongly typed collection. And the use of anonymous methods, while somewhat gratuitous, is very coder cool. I wouldn't recommend this for all situations but it seems like it would be perfect and elegant for quick one off collections.

 

Of course, if you're creating a collection that has any legs, you would probably be better off using one of the other, more generic, reusable solutions. But, man, that's hot! :cool: Thanks for posting that code up, marble_eater. I think that code just made my day.

 

References just for kicks:

http://msdn2.microsoft.com/en-us/library/bfcke1bz.aspx

http://msdn2.microsoft.com/en-us/library/0yw3tz5k.aspx

Posted

It just so happens that i do have a reason to fix up my code. And i greatly appreciate the predicate sample code - couldn't come across that on Google.

 

What happened was I wrote my Equals override to test if the name prop was the same between my test case and my collection. But then I got to a point where the comparison needed to be on the Name and Whatever props. So I can't re-write the Equals to have it work for both cases.

 

I don't have a solution yet for this. Seems like I need to pass in a param to tell my compare (or equals) method what exactly I want compared. The hack I came up with was to just create my own method for each kind of comparison so that the things you are comparing are actually in the name of the method so I have a method for CompareName and CompareWhatever and they behave differently. Being the experienced programmer that i am I can sniff out (and mastermind) a giant hack from around the corner. There has to be a better way but it does boil down to the fact that the comparing method needs to know what to compare.

 

Any ideas? Seems like this is what delegates are made for but i'm a little lost in that area.

And I greatly appreciate the support.

Wanna-Be C# Superstar
Posted (edited)

I was thinking about maybe using predicates for something similar I'm working on. http://www.xtremedotnettalk.com/showthread.php?t=97412

 

Is it possible to do something similar to this with predicates?Or is that to much? Any tutorials on them?That has me curious.So this is something new with 2005?

 

Or maybe not allow duplicates in added into the list in the first place and tally the totals to the first instance of that player object.

 

This is what the List class looks like...

Imports System
Imports System.IO
Imports System.Net
Imports System.Web



Public Class CPlayerList1
   Private m_Players As New Collection
   Private Player As CPlayer

   


   Public Sub New()

       'empty constructor

   End Sub



   Public Sub LoadPlayers()
       Try
           Const file As String = "pathtoftp"
           Dim client As New WebClient
           Dim ftpReq As FtpWebRequest = _
              WebRequest.Create(file)
           ftpReq.Method = WebRequestMethods.Ftp.DownloadFile
           ftpReq.KeepAlive = True
           ftpReq.UsePassive = True

           ftpReq.Credentials = New NetworkCredential( _
              "nunya", "business")
           Dim ftpResp As FtpWebResponse

           ftpResp = ftpReq.GetResponse
           Dim ftpRespStream As Stream
           Dim reader As StreamReader
           ftpRespStream = ftpResp.GetResponseStream
           Stream.Synchronized(ftpRespStream)
           reader = New IO.StreamReader(ftpRespStream, _
              System.Text.Encoding.ASCII)

           Do While StreamReader.Synchronized(reader).Read
               Dim myPlayer As String
               myPlayer = reader.ReadLine
               GetNames(myPlayer)
               GetKills(myPlayer)
               getDeaths(myPlayer)
               GetTk(myPlayer)
               GetSuicides(myPlayer)
               GetObjective(myPlayer)

           Loop
           reader.Close()



       Catch ex As Exception
           Dim mm As New System.Net.Mail.SmtpClient
           mm.Host = "smtp.charter.net"
           mm.Send("itower@chartermi.net", "itower@chartermi.net", "error", ex.Message)
       End Try
   End Sub
   Private Sub WritePlayers(ByVal Path As String)

   End Sub
  
   Private Sub GetObjective(ByVal myObjective As String)
       Dim myplayernames As String
       myplayernames = getPlayersObjective(myObjective)
       If myplayernames <> "" Then

           Player.Objective = getPlayersObjective(myObjective)
           m_Players.Add(Player) 'Add our player to our collection of players.####NOTE HERE####
       End If
   End Sub
   Private Function getPlayersObjective(ByVal myObjective As String)
       Dim reg As Regex = New Regex("Objective:+\s*\w*")
       Dim m As Match = reg.Match(myObjective)
       myObjective = m.Value.Replace("Objective: ", "")

       Return myObjective
   End Function

   Private Sub GetTk(ByVal tk As String)
       Dim myplayernames As String
       myplayernames = GetPlayerTeamKills(tk)
       If myplayernames <> "" Then

           Player.TeamKills = GetPlayerTeamKills(tk)
       

       End If
   End Sub
   Private Sub getDeaths(ByVal mydeaths As String)
       Dim myplayernames As String
       myplayernames = GetPlayerDeaths(mydeaths)
       If myplayernames <> "" Then

           Player.Deaths = GetPlayerDeaths(mydeaths)
           

       End If
   End Sub
   Private Sub GetNames(ByVal myNames As String)
       Dim myplayernames As String
       myplayernames = GetPlayerNames(myNames)
       If myplayernames <> "" Then
           Player = New CPlayer
           Player.Name = GetPlayerNames(myNames)
           

       End If
   End Sub
   Private Sub GetKills(ByVal amyKills As String)
       Dim myTempKills As String
       myTempKills = GetPlayerKills(amyKills)
       If myTempKills <> "" Then
           Player.Kills = GetPlayerKills(amyKills)
           

       End If
   End Sub
   Private Sub GetSuicides(ByVal mySuicides As String)
       Dim myTempKills As String
       myTempKills = GetPlayerSuicides(mySuicides)
       If myTempKills <> "" Then
           Player.Suicides = GetPlayerSuicides(mySuicides)
           

       End If
   End Sub
   Public Function GetPlayerSuicides(ByVal mySuicides As String)
       Dim reg As Regex = New Regex("Suicides:+\s*\w*")
       Dim m As Match = reg.Match(mySuicides)
       mySuicides = m.Value.Replace("Suicides: ", "")
       Return mySuicides
   End Function
   Public Function GetPlayerDeaths(ByVal myDEaths As String) As String
       Dim reg As Regex = New Regex("Deaths:+\s*\w*")
       Dim m As Match = reg.Match(myDEaths)
       myDEaths = m.Value.Replace("Deaths: ", "")

       Return myDEaths
   End Function
   Public Function GetPlayerNames(ByVal myPlayer As String) As String
       Dim reg As Regex = New Regex("\:+\s[a-zA-Z0-9<>?,.{}}\+_&=!@#$'%-|`*^:/;()~]+\s+\(u*")
       Dim m As Match = reg.Match(myPlayer)
       myPlayer = m.Value.TrimStart(": ").ToString 'changed test players
       Dim temp As String = myPlayer.Replace("(u", "  ")

       Return temp
   End Function


   Public Function GetPlayerKills(ByVal myKills As String) As String
       Dim reg As Regex = New Regex("]+\sKills:+\s+\w+")
       Dim m As Match = reg.Match(myKills)
       myKills = m.Value.TrimStart("]")
       myKills = myKills.Replace("Kills: ", "")

       Return myKills
   End Function
   Public Function GetPlayerTeamKills(ByVal myTk As String) As String
       Dim reg As Regex = New Regex("m\s*\sKills:\s*\w*")
       Dim m As Match = reg.Match(myTk)
       Dim temp As String = m.Value.Replace("m ", "")
       temp = temp.Replace("Kills:", "")
       Return temp
   End Function
   Public Shared Function fGETDATE(ByVal myString As String) As String
       Dim reg As Regex = New Regex("((?<=\[)[^\[\]]*)")
       Dim m As Match = reg.Match(myString)
       myString = m.Value.ToString
       reg = Nothing

       Return myString
   End Function
   Public Function Players() As Collection
       Return m_Players
   End Function
   Public Sub RemovePlayer(ByVal index As Integer)
       m_Players.Remove(index)
   End Sub
   Public Function GetPLAYERCount() As Integer
       Return m_Players.Count
   End Function
   Public Function GetPLAYERObject(ByVal index As Integer) As CPlayer
       Return m_Players.Item(index)
   End Function

End Class

Edited by AFterlife
Posted

AFterlife, I don't want to dump too hard on you or anything, but you might find more success by starting a new thread rather than hijacking this one. This thread is covering techniques for searching through a list of objects not using predicates to help refactor code. Generally speaking, it's easier to navigate the forums if one thread == one subject.

 

I'm sure if you were to start a new thread with a more appropriate subject header you'll grab more people's attention and probably get more responses. :)

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...