Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

230
Vistas
Manera eficiente de eliminar la mitad de los elementos duplicados en una lista

Si tengo una lista, digamos l = [1, 8, 8, 8, 1, 3, 3, 8] y está garantizado que cada elemento aparece un número par de veces, ¿cómo hago una lista con todos los elementos de l ahora? ocurriendo n/2 veces. Entonces, dado que 1 ocurrió 2 veces, ahora debería ocurrir una vez. Dado que 8 ocurre 4 veces, ahora debería ocurrir dos veces. Dado que 3 ocurrió dos veces, debería ocurrir una vez.

Así que la nueva lista será algo así como k=[1,8,8,3]

¿Cuál es la forma más rápida de hacer esto? Hice list.count() para cada elemento pero fue muy lento.

over 4 years ago · Santiago Trujillo
12 Respuestas
Responde la pregunta

0

Utilice un contador para realizar un seguimiento del recuento de cada elemento

 from collections import Counter l = [1,8,8,8,1,3,3,8] res = [] count = Counter(l) # its like dict(1: 2, 8: 4, 3: 2) for key, val in count.items(): res.extend(val//2 * [key]) print(res) # output [1, 8, 8, 3]
over 4 years ago · Santiago Trujillo Denunciar

0

Si no le preocupa conservar el orden relativo, primero puede obtener un recuento de cada elemento usando collections.Counter y luego crear una nueva lista con cada elemento duplicado la mitad de veces.

 >>> from collections import Counter >>> from itertools import chain >>> list(chain.from_iterable([key]*(count//2) for key, count in Counter(l).items())) [1, 8, 8, 3]
over 4 years ago · Santiago Trujillo Denunciar

0

Tal vez esto.

 newList = [] for number in l: if(newList.count(number) < l.count(number)/2): newList.append(number) print(newList)
over 4 years ago · Santiago Trujillo Denunciar

0

Si el orden no es importante, una forma sería obtener los índices pares o impares solo después de una ordenación. Esas listas serán las mismas, por lo que solo necesita una de ellas.

 l = [1,8,8,8,1,3,3,8] l.sort() # Get all odd indexes odd = l[1::2] # Get all even indexes even = l[::2] print(odd) print(odd == even)

Resultado:

 [1, 3, 8, 8] True
over 4 years ago · Santiago Trujillo Denunciar

0

Dado que garantiza que cada elemento de la lista sea un múltiplo de 2, entonces es más rápido crear el contador a medida que crea la lista de salida, en lugar de crear un contador (o ordenar) primero y usarlo más tarde.

 l = [1,8,8,8,1,3,3,8] count={} res=[] for i in l: if i in count: count[i]+=1 else: count[i]=1 if count[i]%2: res.append(i) print(res)

Producción

 [1,8,8,3]

EDITAR Comparando tiempo/gasto de cada método

El uso del módulo timeit muestra que este enfoque es 2,7 veces más rápido que el uso de un contador primero.

es decir

 def one(): l = [1,8,8,8,1,3,3,8] count={} res=[] for i in l: if i in count: count[i]+=1 else: count[i]=1 if count[i]%2: res.append(i) #print(res) def two(): from collections import Counter l = [1,8,8,8,1,3,3,8] res = [] count = Counter(l) # its like dict(1: 2, 8: 4, 3: 2) for key, val in count.items(): res.extend(val//2 * [key]) o=timeit.Timer(one) t=timeit.Timer(two) print(o.timeit(100000)) print(t.timeit(100000)) print(o.timeit(100000)) print(t.timeit(100000))

Salida (segundos)

 0.28666 0.80822 0.28678 0.80113

Si el orden no es importante, entonces se preferiría el método de Wimanicesir con una aceleración 4 veces mayor, con un resultado de 0.07037 (~11 veces más rápido que con el enfoque contrario).

ACTUALIZACIÓN Sospechaba que usar el método Counter en two (desordenado) puede generar un aumento significativo o una ralentización en la importación, así que probé el método "contar primero, compilar el resultado después" mientras contaba con el método simple aquí desde one (ordenado)

 count={} for i in l: if i in count: count[i]+=1 else: count[i]=1

que era mucho más rápido que Counter . Reemplazar Counter en two de las pruebas definidas resultó en un tiempo de 0,31 en lugar de 0,80. Sin embargo, aún es un poco más rápido compilar el resultado (ordenado) durante el conteo como en two . Y mucho más rápido para resultados desordenados al usar el método de Wimanicesir.

over 4 years ago · Santiago Trujillo Denunciar

0

mantiene una lista de todos los elementos que se han visitado un número impar de veces. luego itera sobre todos los elementos de la lista.

en otros idiomas, probablemente usaría algún método map() o filter(), pero aquí hay un código simple ya que no conozco Python lo suficientemente bien. :)

 l = [1,8,8,8,1,3,3,8] seen = [] result = [] for num in l: if num in seen: seen.remove(num) #result.append(num) #print every even appearance else: seen.append(num) result.append(num) #print every odd appearance if len(seen)==0: print(result) else: print("Error: uneven elements found:", seen)

al final, la matriz visitada debe estar vacía, por lo que puede usar eso como una verificación de cordura antes de devolver la matriz de resultados.

editar: aquí hay una versión con filtro que devuelve las apariencias extrañas

 l = [1,8,8,8,1,3,3,8] seen = [] result = list(filter(lambda x: seen.append(x) is None if x not in seen else not seen.remove(x) is None, l)) if len(seen)==0: print(result) else: print("Error: uneven elements found:", seen)

y este devuelve las apariencias pares:

 l = [1,8,8,8,1,3,3,8] seen = [] result = list(filter(lambda x: seen.remove(x) is None if x in seen else not seen.append(x) is None, l)) if len(seen)==0: print(result) else: print("Error: uneven elements found:", seen)
over 4 years ago · Santiago Trujillo Denunciar

0

En lugar de usar un contador, que realiza un seguimiento de un número entero para cada elemento posible de la lista, intente asignar elementos a booleanos usando un diccionario. Asigne a verdadero la primera vez que se ven, y luego cada vez después de eso, cambie el bit, y si es verdadero, omita el elemento.

over 4 years ago · Santiago Trujillo Denunciar

0

Este es un caso de uso clásico de conjuntos y estoy bastante sorprendido de que nadie más lo haya probado para ver cómo se compara con las implementaciones de Counter y dict .

Implementé una solución usando set en su lugar de la siguiente manera:

 def set_impl(l): bag = set() res = [] for i in l: if i in bag: res.append(i) bag.remove(i) else: bag.add(i)

Esta implementación es un 28 % más rápida que usar Counter y un 51 % más rápida que usar un diccionario.

La implementación de ordenar y dividir proporcionada por Wimanicesir es la más rápida y brinda resultados 17 veces más rápido que cuando se usa set . Sin embargo, tenga en cuenta que debido a que ordena los elementos antes de eliminar los duplicados, el orden de aparición no se conserva a diferencia de los otros tres.

Aquí están todas las implementaciones sugeridas con el tiempo para la evaluación del rendimiento comparativo.
https://repl.it/@franzalex/StackOverflow-py#removeDuplicateHalf.py

 import random import statistics as stats from collections import Counter as counter from timeit import Timer def slice_impl(l): l.sort() res = l[::2] def dict_impl(l): count={} res=[] for i in l: if i in count: count[i] += 1 else: count[i] = 1 if count[i] % 2: res.append(i) def counter_impl(l): count = counter(l) res = [] for key, val in count.items(): res.extend(val//2 * [key]) def set_impl(l): bag = set() res = [] for i in l: if i in bag: res.append(i) bag.remove(i) else: bag.add(i) def timed_run(): for name, func in {"Sort and Slice": slice_impl, "Dictionary": dict_impl, "Counter": counter_impl, "Set": set_impl}.items(): seq = list(range(50))*2 results = [] print(f"{name} Implementation Results") for i in range(50): if len(results) % 10: random.shuffle(seq) # shuffle after 10 runs results.append(Timer(lambda: func(seq)).timeit(10**4)) # print(f"Run {i+1:02}: {results[i]:.6f}") print("") print(f"Median: {stats.median(results):.6f}") print(f"Mean: {stats.mean(results):.6f}") print(f"Std Dev: {stats.stdev(results):.6f}") print("\n\n") timed_run()

Resultado de la ejecución de la muestra

Ordenar y dividir resultados de implementación

Mediana: 0.009686
Media: 0.009721
Desv estándar: 0.000529


Resultados de la implementación del diccionario

Mediana: 0.230081
Media: 0.227631
Desv estándar: 0.014584


Resultados de la implementación del contador

Mediana: 0.192730
Media: 0.194577
Desv estándar: 0.008015


Establecer resultados de implementación

Mediana: 0.149604
Media: 0.151227
Desv estándar: 0.006838
over 4 years ago · Santiago Trujillo Denunciar

0

import itertools st=time.time() lst = [1,8,8,8,1,3,3,8] list(itertools.chain.from_iterable(itertools.repeat(x, int(lst.count(x)/2)) for x in list(set(lst)) if lst.count(x)%2==0))

Esto da una lista ordenada

over 4 years ago · Santiago Trujillo Denunciar

0

Si el orden es importante, el siguiente código puede funcionar con O(N):

 import collections c = collections.Counter(l) c2 = collections.Counter() i, n = 0, len(l) res=[] for x in l: if i == n//2:break if c2[x] < c[x] // 2: res.append(x) c2[x] += 1 i += 1
over 4 years ago · Santiago Trujillo Denunciar

0

Sé que esto ha sido respondido y hay algunas soluciones bastante largas. Y mencionó específicamente a Python. Sin embargo, pensé que una solución de Powershell podría ser interesante (¡y simple!) para algunos:

Versión 1 (agrupación de elementos - menos eficiente)

 $OriginalArray = @("1","8","8","8","1","3","3","8") $NewArray = New-ObjectSystem.Collections.ArrayList $ArrayGroup = $OriginalArray | Group-Object | Select-Object Count,Name ForEach ($EachNumber in $ArrayGroup) { $HalfTheCount = (1..([Math]::Round($EachNumber.Count / 2))) ForEach ($Item in $HalfTheCount) {$NewArray.Add($EachNumber.Name) | Out-Null} } $NewArray

Versión 2 (elegir todos los demás elementos de una matriz ordenada, más eficiente)

 $OriginalArray = @("1","8","8","8","1","3","3","8") $NewArray = New-Object System.Collections.ArrayList $OddOrEven = "Even" ForEach ($SortedItem in ($OriginalArray | Sort-Object)) { If ($OddOrEven -eq "Even") {$NewArray.Add($SortedItem);$EvenNumber = $True} If ($OddOrEven -eq "Odd") {$EvenNumber = $False} If ($EvenNumber -eq $True) {$OddOrEven = "Odd"} Else {$OddOrEven = "Even"} } $NewArray
over 4 years ago · Santiago Trujillo Denunciar

0

Me gusta usar un conjunto de prueba, ya que necesitas detectar duplicados para eliminarlos, o un gran conjunto de hash (muchos cubos). El trie no se desequilibra y no es necesario saber el tamaño del conjunto final. Una alternativa es un tipo muy paralelo: fuerza bruta.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda