C#Linq intersecta/excepto con una parte del objeto
list except c# (7)
¿Cuál es exactamente el efecto deseado? ¿Desea obtener una lista de cadenas compuestas de todas las a
''s en sus clases, o una lista de ThisClass
, cuando dos instancias de ThisClass
se identifican a través de valores únicos de a
?
Si es el primero, las dos respuestas de @lazyberezovksy y @Tilak deberían funcionar. Si es lo último, deberás anular IEqualityComparer<ThisClass>
o IEquatable<ThisClass>
para que Intersect
sepa qué hace que dos instancias de ThisClass
equivalentes:
private class ThisClass : IEquatable<ThisClass>
{
private string a;
public bool Equals(ThisClass other)
{
return string.Equals(this.a, other.a);
}
}
entonces puedes simplemente llamar:
var intersection = foo.Intersect(bar);
Tengo una clase:
class ThisClass
{
private string a {get; set;}
private string b {get; set;}
}
Me gustaría usar los métodos Intersect y Except de Linq, es decir:
private List<ThisClass> foo = new List<ThisClass>();
private List<ThisClass> bar = new List<ThisClass>();
Luego lleno las dos listas por separado. Me gustaría hacer, por ejemplo (y sé que esto no está bien, solo seudo código), lo siguiente:
foo[a].Intersect(bar[a]);
¿Cómo haría esto?
Debes crear IEqualityComparer. Puede pasar el método IEqualityComparer a Intersect (). Esto le ayudará a obtener la Lista (que se interseca con la barra) más fácil.
var intersectionList = foo.Intersect(bar, new ThisClassEqualityComparer()).ToList();
class ThisClassEqualityComparer : IEqualityComparer<ThisClass>
{
public bool Equals(ThisClass b1, ThisClass b2)
{
return b1.a == b2.a;
}
public int GetHashCode(Box bx)
{
// To ignore to compare hashcode, please consider this.
// I would like to force Equals() to be called
return 0;
}
}
No estoy seguro de la velocidad de esto en comparación con la intersección y la comparación, pero ¿qué hay de:
//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));
Sé que esto es antiguo, pero ¿no podría usted simplemente anular el Equals & GetHashCode en la clase en sí?
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();
}
}
Si desea una lista de una sola propiedad que le gustaría intersectar, entonces todas las otras soluciones bonitas de LINQ funcionan bien. ¡PERO! Si desea cruzar en una clase entera y, como resultado, tener una List<ThisClass>
lugar de List<string>
tendrá que escribir su propio comparador de igualdad.
foo.Intersect(bar, new YourEqualityComparer());
lo mismo con 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
}
Tal vez
// returns list of intersecting property ''a'' values
foo.Select(f => f.a).Intersect(bar.Select(b => b.a));
Por cierto, a
propiedad debe ser pública.
foo.Select(x=>x.a).Intersect(bar.Select(x=>x.a))