Encontrar diferencias en conjuntos

I have this class (a partial listing):

class CiscoSwitch 
{
  private string _SwitchName = string.Empty;
  public SwitchName {get {return _SwitchName;} set{_SwitchName=value; }}
}

I have 2 lists of CiscoSwitch objects. I am trying to compare them to pick out the ones that are not duplicates. I only want the duplicates. I tried a Lambda expression but got a compiler error that CiscoSwitch was a non-delgate type.

I am now wondering about something like this - it would allow me to use the List.Except() method (I think):

static class SwitchComparer
{ 
  static bool CompareSwitchNames(CiscoSwitch s1, CiscoSwitch s2)
         {
            if (sw1.SwitchName == s2.SwitchName) {return true;}
             else {return false;}
         }
}

     // to find the differences 
 // this is a method of the CiscoSwitchClass
private List<CiscoSwitch> FindDifferences(List<CiscoSwitch> List1, List<CiscoSwitch> List2)
{
       return List1.Except(List2, SwitchComparer.CompareSwitchNames();
 }

this could also be done with a foreach but I think this way is a lot cleaner, if it is correct. I am also thinking there are other attributes of a CiscoSwitch I might want to compare some day so could add methods to the SwitchComparer class as I need them.

preguntado el 09 de marzo de 12 a las 17:03

3 Respuestas

No, just having a single method like that won't help you. You need to implement an IEqualityComparer<CiscoSwitch> pasar a Enumerable.Except - and even then your code would need to be:

return List1.Except(List2, new SwitchComparer()).ToList();

Primordial Equals y GetHashCode dentro de CiscoSwitch will do the trick more naturally though - and ideally you should implement IEquatable<CiscoSwitch>

Sin embargo, vale la pena señalar que mudable types like this don't play terribly nicely with things like Dictionary<,> - if you change an object in a way which affects its hash code after you've inserted it as a key into the dictionary, you won't be able to get at it again. Consider making the type immutable if you can.

Un par de otros puntos a tener en cuenta:

  • Any time you write:

    if (condition)
    {
        return true;
    }
    else
    {
        return false;
    }
    

    you should instead write the muchos más simple:

    return condition;
    

    Entonces tus CompareSwitchNames el método sería:

    static bool CompareSwitchNames(CiscoSwitch s1, CiscoSwitch s2) { return s1.SwitchName == s2.SwitchName; }

  • Your parameter names for FindDifferences should follow .NET naming conventions (e.g. list1 y list2)

  • Usar Except will only find you the elements in the first list which aren't in the second list; if you need to find the symmetric difference, consider using HashSet<T> explícitamente

EDIT: If you wanted to have multiple ways of comparing, you could have something like:

public static class SwitchComparers
{
    public static readonly IEqualityComparer<CiscoSwitch> ByName =
        new ByNameComparer();

    public static readonly IEqualityComparer<CiscoSwitch> ByCost =
        new ByCostComparer();


    private sealed class ByNameComparer : IEqualityComparer<CiscoSwitch>
    {
        // Implementation
    }

    private sealed class ByCostComparer : IEqualityComparer<CiscoSwitch>
    {
        // Implementation
    }
}

respondido 09 mar '12, 17:03

Except would miss all the unique elements in List2 - as far as I can tell that's not what OP wants - Vidrio roto

@BrokenGlass: Yup, was adding an edit which included that at the end :) - jon skeet

thanks for the explanation. Is it good practice not to make the class that implements IEqualityComparer static? My thinking is/was that I could then compare other attributes of a CiscoSwitch object using the same static class by having different methods. If I understand the MSDN examples and the code posted here, without the static class I would need one class for each attribute I wanted to compare. - David Green

@DavidGreen: A class which implements an interface no puedes be static. You could create several different implementations of IEqualityComparer<T> and have static properties which return them, admittedly. (Those different implementations could be private nested classes within a static class, if you want. See my edit for an example.) - jon skeet

@JonSkeet after I asked that I thought I remembered that about static classes. I tried it in VS and it complained. :) Looking at your code, a static class doesn't seem to add much if I still need to implement separate classes anyway. - David Green

You could implement a custom comparer:

 public class CiscoSwitchComparer : IEqualityComparer<CiscoSwitch>
 {
   public bool Equals(CiscoSwitch x, CiscoSwitch y)
   {
       return x.SwitchName.Equals(y.SwitchName));
   }

   public int GetHashCode(CiscoSwitch obj)
   {
       return obj.SwitchName.GetHashCode();
   }
 }

Y entonces:

private List<CiscoSwitch> FindDifferences(List<CiscoSwitch> List1, List<CiscoSwitch> List2)
{
    return List1.Concat(List2)
                .Distinct(new CiscoSwitchComparer())
                .ToList();
}

respondido 09 mar '12, 17:03

From MSDN: We recommend that you derive from the EqualityComparer class instead of implementing the IEqualityComparer interface - jakub konecki

Mhh got any source for that? I don't see anything wrong with my implementation that would warrant a downvote - Vidrio roto

Deberías implementar IEqualityComparer[T] de la interfaz del.

This interface allows the implementation of customized equality comparison for collections. That is, you can create your own definition of equality for type T, and specify that this definition be used with a collection type that accepts the IEqualityComparer generic interface. In the .NET Framework, constructors of the Dictionary generic collection type accept this interface.

A default implementation of this interface is provided by the Default property of the EqualityComparer generic class. The StringComparer class implements IEqualityComparer of type String.

This interface supports only equality comparisons. Customization of comparisons for sorting and ordering is provided by the IComparer generic interface.

We recommend that you derive from the EqualityComparer class instead of implementing the IEqualityComparer interface, because the EqualityComparer class tests for equality using the IEquatable.Equals method instead of the Object.Equals method. This is consistent with the Contains, IndexOf, LastIndexOf, and Remove methods of the Dictionary class and other generic collections.

respondido 09 mar '12, 17:03

Not for Except. We're not trying to do ordering, we're checking for equality. - jon skeet

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.