web-dev-qa-db-fra.com

C # Linq intersecter/sauf avec une partie d'objet

J'ai un cours:

class ThisClass
{
  private string a {get; set;}
  private string b {get; set;}
}

Je voudrais utiliser les méthodes Intersect et Except de Linq, à savoir:

private List<ThisClass> foo = new List<ThisClass>();
private List<ThisClass> bar = new List<ThisClass>();

Ensuite, je remplis les deux listes séparément. J'aimerais faire, par exemple (et je sais que ce n'est pas juste, juste du pseudo code), ce qui suit:

foo[a].Intersect(bar[a]);

Comment je ferais ça?

21
David Archer

Peut être

// returns list of intersecting property 'a' values
foo.Select(f => f.a).Intersect(bar.Select(b => b.a));

La propriété BTW a devrait être publique.

27

Si vous voulez une liste d'une seule propriété que vous souhaitez intersecter, toutes les autres jolies solutions LINQ fonctionnent parfaitement. MAIS! Si vous souhaitez toutefois croiser une classe entière et avoir un List<ThisClass> au lieu de List<string>, vous devrez écrire votre propre comparateur d'égalité.

foo.Intersect(bar, new YourEqualityComparer());

idem avec Except.

public class YourEqualityComparer: IEqualityComparer<ThisClass>
{

    #region IEqualityComparer<ThisClass> Members


    public bool Equals(ThisClass x, ThisClass y)
    {
        //no null check here, you might want to do that, or correct that to compare just one part of your object
        return x.a == y.a && x.b == y.b;
    }


    public int GetHashCode(ThisClass obj)
    {
        unchecked
        {
            var hash = 17;
                            //same here, if you only want to get a hashcode on a, remove the line with b
            hash = hash * 23 + obj.a.GetHashCode();
            hash = hash * 23 + obj.b.GetHashCode();

            return hash;    
        }
    }

    #endregion
}
22
Patryk Ćwiek

Pas sûr de la vitesse de cette comparaison par rapport à intersecter et comparer mais que diriez-vous:

//Intersect
var inter = foo.Where(f => bar.Any(b => b.a == f.a));
//Except - values of foo not in bar
var except = foo.Where(f => !bar.Any(b => b.a == f.a));
3
Zach Johnson
foo.Select(x=>x.a).Intersect(bar.Select(x=>x.a))
2
Tilak

Quel est exactement l'effet désiré? Voulez-vous obtenir une liste de chaînes composées de tous les as de vos classes ou une liste de ThisClass, lorsque deux instances de ThisClass sont identifiées via des valeurs uniques de a?

Si c’est le premier cas, les deux réponses de @lazyberezovksy et @Tilak devraient fonctionner. Si c'est le dernier cas, vous devrez remplacer IEqualityComparer<ThisClass> ou IEquatable<ThisClass> pour que Intersect sache ce qui rend deux instances de ThisClass équivalentes:

 private class ThisClass : IEquatable<ThisClass>
 {
     private string a;

     public bool Equals(ThisClass other)
     {
        return string.Equals(this.a, other.a);
     }
 }

alors vous pouvez simplement appeler:

 var intersection = foo.Intersect(bar);     
0

Je sais que c'est vieux, mais ne pourriez-vous pas également remplacer le Equals & GetHashCode sur la classe elle-même?

class ThisClass
{
  public string a {get; set;}
  private string b {get; set;}

  public override bool Equals(object obj)
  {
    // If you only want to compare on a
    ThisClass that = (ThisClass)obj;
    return string.Equals(a, that.a/* optional: not case sensitive? */);
  }

  public override int GetHashCode()
  {
    return a.GetHashCode();
  }
}
0
tyr