2010-04-28 146 views
11

Quiero contar los mismos elementos de dos listas. Las listas pueden tener elementos duplicados, por lo que no puedo convertir esto en conjuntos y usar el operador &.Elementos comunes entre dos listas que no usan conjuntos en Python

a=[2,2,1,1] 
b=[1,1,3,3] 

conjunto (a) & conjunto (b) trabajar
un & B ya no funcionan

Es posible hacerlo withoud establece y Dictonary?

+0

¿Por qué no desea utilizar conjuntos? –

+1

Tengo elementos duplicados en la lista – Thomas

+2

¿cuáles son los valores de retorno esperados para '[1, 2, 1]' y '[1, 3, 2]'? – SilentGhost

Respuesta

8

Usar conjuntos es el más eficiente, pero siempre se puede hacer r = [i for i in l1 if i in l2].

+0

Una diferencia clara: el método set() y set() sugerido devolverá un único valor que es común entre las dos listas (set ([1]) en este ejemplo) mientras que su solución devolverá [1, 1] y así en. –

+0

Gracias, pero ¿es una solución más perfomance? – Thomas

+0

Quiero la función que devuelve [1,1] – Thomas

11

En Python 3.x (y Python 2.7, cuando salga al mercado), se puede utilizar para este collections.Counter:

>>> from collections import Counter 
>>> list((Counter([2,2,1,1]) & Counter([1,3,3,1])).elements()) 
[1, 1] 

Aquí es una alternativa usando collections.defaultdict (disponible en Python 2.5 y posteriores). Tiene la buena propiedad de que el orden del resultado es determinista (esencialmente corresponde al orden de la segunda lista).

from collections import defaultdict 

def list_intersection(list1, list2): 
    bag = defaultdict(int) 
    for elt in list1: 
     bag[elt] += 1 

    result = [] 
    for elt in list2: 
     if elt in bag: 
      # remove elt from bag, making sure 
      # that bag counts are kept positive 
      if bag[elt] == 1: 
       del bag[elt] 
      else: 
       bag[elt] -= 1 
      result.append(elt) 

    return result 

Por estas dos soluciones, el número de ocurrencias de cualquier elemento dado x en la lista de salida es el mínimo de los números de ocurrencias de x en las dos listas de entrada. No queda claro a partir de su pregunta si este es el comportamiento que desea.

+0

'if bag [elt]:' agrega un elemento 'elt: 0' a la bolsa cuando' elt in bag' es falso. Cuando (como el OP insinuó) hay pocos duplicados, puede ser mejor hacer 'si elt en bolsa y bolsa [elt]:' de lo contrario la bolsa puede hincharse con 0 valores inútiles. –

+0

@John Machin: Hmm. Buen punto. Una alternativa sería asegurarse de que los recuentos de bolsas siempre sean estrictamente positivos, siguiendo 'bag [elt] - = 1' con un' if not bag [elt]: del bag [elt] '. Entonces, la prueba 'if' podría ser' si elt in bag: ', que se lee con más facilidad. Voy a editar la respuesta. –

0

SilentGhost, Mark Dickinson y Lo'oris son correctas, Muchas gracias por el informe de este problema - Necesito parte común de las listas, por lo que para:

a = [1,1,1,2]

b = [1,1,3,3]

resultado debe ser [1,1]

este momento para hacer comentarios en su lugar no es adecuado - hoy me he registrado.

he modificado soluciones suyo:

def count_common(l1,l2): 
     l2_copy=list(l2) 
     counter=0 
     for i in l1: 
      if i in l2_copy: 
       counter+=1 
       l2_copy.remove(i) 
     return counter 

l1=[1,1,1] 
l2=[1,2] 
print count_common(l1,l2) 

+4

¡bienvenido! Es posible que desee enviar un correo electrónico a 'team @ stackoverflow.com' y pedirles que fusionen su cuenta recién registrada con la cuenta temporal anterior. Ver: http://meta.stackexchange.com/questions/18232/how-can-one-link-merge-combine-associate-two-stack-overflow-accounts-users-anon –

Cuestiones relacionadas