¿Alguna idea sobre cómo verificar si esa lista es un subconjunto de otra?
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?
Respuestas:
fuente
Use HashSet en lugar de List si trabaja con conjuntos. Entonces puedes simplemente usar IsSubsetOf ()
Lamento que no use LINQ. :-(
Si necesita usar listas, la solución de @ Jared funciona con la advertencia de que deberá eliminar cualquier elemento repetido que exista.
fuente
Si realiza pruebas unitarias también puede utilizar el método CollectionAssert.IsSubsetOf :
En el caso anterior esto significaría:
fuente
Esta es una solución significativamente más eficiente que las otras publicadas aquí, especialmente la solución principal:
Si puede encontrar un solo elemento en t2 que no está en t1, entonces sabe que t2 no es un subconjunto de t1. La ventaja de este método es que se realiza todo en el 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 abreviada anterior.
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 () y .Intersect (), y no utilizan memoria adicional.
fuente
!t2.Except(t1).Any()
está haciendo. Linq está trabajando de ida y vuelta.Any()
está preguntandoIEnumerable
si hay al menos un elemento. En este escenariot2.Except(t1)
solo se emite el primer elemento delt2
cual no estát1
. Si el primer elemento det2
no está ent1
él, termina más rápido, si todos los elementos de sít2
están ent1
él, dura más.t1={1,2,3,...9999}
yt2={9999,9998,99997...9000}
, se obtiene las siguientes medidas:!t2.Except(t1).Any(): 1ms -> t2.All(e => t1.Contains(e)): 702ms
. Y empeora cuanto mayor es el rango.t2.Except (t1)
está devolviendo unIEnumerable
no aCollection
. Solo emite todos los elementos posibles si itera completamente sobre él, por ejemplo, medianteToArray ()
o sinToList ()
usarforeach
dentro. Busque la ejecución diferida de linq para leer más sobre ese concepto.t2={1,2,3,4,5,6,7,8}
t1={2,4,6,8}
t2.Except(t1)
=> primer elemento de t2 = 1 => la diferencia de 1 a t1 es 1 (verificado con {2,4,6,8}) =>Except()
emite el primer elemento 1 =>Any()
obtiene un elemento =>Any()
da como resultado verdadero => no más verificación de elementos en t2.La solución de @ Cameron como método de extensión:
Uso:
(Esto es similar, pero no exactamente igual al publicado en el blog de @ Michael)
fuente
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.
fuente
p.ej:
fuente
Prueba esto
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 el conjunto original, todos los elementos en "set" también están en "check" y, por lo tanto, "set" es un subconjunto de "toCheck"
Nota: Mi solución no funciona si "set" tiene duplicados. No lo voy a cambiar porque no quiero robar los votos de otras personas.
Pista: voté por la respuesta de Cameron.
fuente