c# - query - Verificar si una matriz es un subconjunto de otra
linq c# tutorial español (7)
¿Alguna idea sobre cómo verificar si esa lista es un subconjunto de otro?
Específicamente, tengo
List<double> t1 = new List<double> { 1, 3, 5 };
List<double> t2 = new List<double> { 1, 5 };
¿Cómo verificar que t2 es un subconjunto de t1, usando LINQ?
@ La solución de Cameron como método de extensión:
public static bool IsSubsetOf<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
return !a.Except(b).Any();
}
Uso:
bool isSubset = t2.IsSubsetOf(t1);
(Esto es similar, pero no es lo mismo que el publicado en el blog de @ Michael)
Esta es una solución significativamente más eficiente que las otras publicadas aquí, especialmente la mejor solución:
bool isSubset = t2.All(elem => t1.Contains(elem));
Si puede encontrar un solo elemento en t2 que no esté en t1, entonces sabrá que t2 no es un subconjunto de t1. La ventaja de este método es que se realiza en su lugar, sin asignar espacio adicional, a diferencia de las soluciones que usan .Except o .Intersect. Además, esta solución puede romperse tan pronto como encuentre un solo elemento que viole la condición del subconjunto, mientras que los demás continúan buscando. A continuación se muestra la forma larga óptima de la solución, que es solo marginalmente más rápida en mis pruebas que la solución de taquigrafía anterior.
bool isSubset = true;
foreach (var element in t2) {
if (!t1.Contains(element)) {
isSubset = false;
break;
}
}
Hice un análisis de rendimiento rudimentario de todas las soluciones, y los resultados son drásticos. Estas dos soluciones son aproximadamente 100 veces más rápidas que las soluciones .Except () e .Intersect () y no usan memoria adicional.
Prueba esto
static bool IsSubSet<A>(A[] set, A[] toCheck) {
return set.Length == (toCheck.Intersect(set)).Count();
}
La idea aquí es que Intersect solo devolverá los valores que están en ambas matrices. En este punto, si la longitud del conjunto resultante es la misma que la del conjunto original, entonces todos los elementos en "conjunto" también están en "control" y, por lo tanto, "conjunto" es un subconjunto de "controlar".
Nota: Mi solución no funciona si "set" tiene duplicados. No lo estoy cambiando porque no quiero robar los votos de otras personas.
Sugerencia: voté por la respuesta de Cameron.
Si está realizando pruebas unitarias, también puede utilizar el método CollectionAssert.IsSubsetOf :
CollectionAssert.IsSubsetOf(subset, superset);
En el caso anterior, esto significaría lo siguiente:
CollectionAssert.IsSubsetOf(t2, t1);
Sobre la base de las respuestas de @Cameron y @Neil escribí un método de extensión que usa la misma terminología que la clase Enumerable.
/// <summary>
/// Determines whether a sequence contains the specified elements by using the default equality comparer.
/// </summary>
/// <typeparam name="TSource">The type of the elements of source.</typeparam>
/// <param name="source">A sequence in which to locate the values.</param>
/// <param name="values">The values to locate in the sequence.</param>
/// <returns>true if the source sequence contains elements that have the specified values; otherwise, false.</returns>
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> values)
{
return !values.Except(source).Any();
}
Use HashSet en lugar de List si trabaja con sets. Entonces simplemente puede usar IsSubsetOf()
HashSet<double> t1 = new HashSet<double>{1,3,5};
HashSet<double> t2 = new HashSet<double>{1,5};
bool isSubset = t2.IsSubsetOf(t1);
Lamento que no use LINQ. :-(
Si necesita usar listas, la solución de @Jared funciona con la advertencia de que necesitará eliminar cualquier elemento repetido que exista.
bool isSubset = !t2.Except(t1).Any();