¿Cómo verificar si todos los elementos de una lista están en otra lista?

Tengo dos listas que dicen

List1 = ['a','c','c'] List2 = ['x','b','a','x','c','y','c'] 

Ahora quiero saber si todos los elementos de List1 están allí en List2. En este caso todo lo que hay. No puedo usar la función de subconjunto porque puedo tener elementos repetidos en las listas. Puedo usar un bucle for para contar la cantidad de ocurrencias de cada elemento en la Lista1 y ver si es menor o igual que la cantidad de ocurrencias en la Lista2. ¿Hay una mejor manera de hacer esto?

Gracias.

Cuando el número de ocurrencias no importa, aún puede usar la funcionalidad de subconjunto, creando un conjunto sobre la marcha:

 >>> list1 = ['a', 'c', 'c'] >>> list2 = ['x', 'b', 'a', 'x', 'c', 'y', 'c'] >>> set(list1) < set(list2) True 

Si necesita comprobar si cada elemento aparece al menos tantas veces en la segunda lista como en la primera lista, puede utilizar el tipo de contador y definir su propia relación de subconjunto:

 >>> from collections import Counter >>> def counterSubset(list1, list2): c1, c2 = Counter(list1), Counter(list2) for k, n in c1.items(): if n > c2[k]: return False return True >>> counterSubset(list1, list2) True >>> counterSubset(list1 + ['a'], list2) False >>> counterSubset(list1 + ['z'], list2) False 

Si ya tiene contadores (lo que podría ser una alternativa útil para almacenar sus datos de todos modos), también puede escribir esto como una sola línea:

 >>> all(n <= c2[k] for k, n in c1.items()) True 

Tenga en cuenta lo siguiente:

 >>>listA = ['a', 'a', 'b','b','b','c'] >>>listB = ['b', 'a','a','b','c','d'] >>>all(item in listB for item in listA) True 

Si lees la línea “todo” como lo harías en inglés, esto no es incorrecto pero puede ser engañoso, ya que listA tiene una tercera ‘b’ pero listB no.

Esto también tiene el mismo problema:

 def list1InList2(list1, list2): for item in list1: if item not in list2: return False return True 

Solo una nota. Lo siguiente no funciona:

 >>>tupA = (1,2,3,4,5,6,7,8,9) >>>tupB = (1,2,3,4,5,6,6,7,8,9) >>>set(tupA) < set(TupB) False 

Si convierte las tuplas a listas, todavía no funciona. No sé por qué las cuerdas funcionan, pero las intenciones no.

Funciona pero tiene el mismo problema de no llevar la cuenta de ocurrencias de elementos:

 >>>set(tupA).issubset(set(tupB)) True 

El uso de conjuntos no es una solución integral para la coincidencia de elementos de múltiples ocurrencias.

Pero aquí hay una solución / adaptación de una sola línea a la respuesta de shantanoo sin intentar / excepto:

 all(True if sequenceA.count(item) <= sequenceB.count(item) else False for item in sequenceA) 

Una función incorporada que encierra una lista de comprensión utilizando un operador condicional ternario. Python es impresionante! Tenga en cuenta que el "<=" no debe ser "==".

Con esta solución, las secuencias A y B pueden ser de tipo tupla y lista y otras "secuencias" con métodos de "conteo". Los elementos en ambas secuencias pueden ser la mayoría de los tipos. No usaría esto con los dicts como está ahora, de ahí el uso de "secuencia" en lugar de "iterable".

Una solución que utiliza Counter y el método de intersección incorporado (tenga en cuenta que - es la diferencia de conjuntos múltiples adecuada, no una resta de elementos):

 from collections import Counter def is_subset(l1, l2): c1, c2 = Counter(l1), Counter(l2) return not c1 - c2 

Prueba:

 >>> List1 = ['a','c','c'] >>> List2 = ['x','b','a','x','c','y','c'] >>> is_subset(List1, List2) True 

No puedo usar la función de subconjunto porque puedo tener elementos repetidos en las listas.

Lo que esto significa es que desea tratar sus listas como multisets en lugar de conjuntos . La forma habitual de manejar multisets en Python es con collections.Counter .

Un Counter es una subclase dict para contar objetos hashable. Es una colección desordenada donde los elementos se almacenan como claves de diccionario y sus conteos se almacenan como valores de diccionario. Se permite que las cuentas sean cualquier valor entero, incluyendo cuentas cero o negativas. La clase Counter es similar a las bolsas o conjuntos múltiples en otros idiomas.

Y, aunque puede implementar un subconjunto para conjuntos múltiples (implementado con Counter ) haciendo un bucle y comparando los conteos, como en la respuesta de Poke , esto no es necesario, al igual que puede implementar un subconjunto para conjuntos (implementado con set o frozenset ) realizando un bucle y probando, pero es innecesario

El tipo de Counter ya implementa todos los operadores de conjuntos extendidos de forma obvia para los conjuntos múltiples. <1 Por lo tanto, solo puede escribir un subconjunto en términos de esos operadores, y funcionará tanto para el set como para el Counter fuera de la caja.

Con (multi) ajustar la diferencia: 2

 def is_subset(c1, c2): return not c1 - c2 

O con (multi) conjunto de intersección:

 def is_subset(c1, c2): def c1 & c2 == c1 

1. Es posible que se pregunte por qué, si Counter implementa los operadores de conjuntos, no solo implementa < y <= para el subconjunto y subconjunto adecuados. Aunque no puedo encontrar el hilo del correo electrónico, estoy bastante seguro de que esto fue discutido, y la respuesta fue que "los operadores de conjuntos" se definen como el conjunto específico de operadores definidos en la versión inicial de collections.abc.Set (que desde entonces se ha expandido, IIRC ...), no todos los operadores que set incluyen por conveniencia, exactamente de la misma manera que Counter no tiene métodos con nombre, como la intersection que sea amigable para otros tipos, & solo porque lo hace.

2. Esto depende del hecho de que se espera que las colecciones en Python sean false cuando estén vacías y, de lo contrario, de verdad. Esto se documenta aquí para los tipos incorporados, y el hecho de que las pruebas bool se bool a len se explica aquí, pero en última instancia es solo una convención, de modo que las "cuasi colecciones" como matrices numpy pueden violarla si tienen una buena razón. Se aplica a "colecciones reales" como Counter , OrderedDict , etc. Si está realmente preocupado por eso, puede escribir len(c1 - c2) == 0 , pero tenga en cuenta que esto va en contra del espíritu de PEP 8 .

 def check_subset(list1, list2): try: [list2.remove(x) for x in list1] return 'all elements in list1 are in list2' except: return 'some elements in list1 are not in list2' 

Esto devolverá verdadero si todos los elementos en Lista1 están en Lista2

 def list1InList2(list1, list2): for item in list1: if item not in list2: return False return True