Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

225
Views
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 answers
Answer question

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 Report

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 Report

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 Report

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 Report

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 Report

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 Report

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 Report

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 Report

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 Report

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 Report

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!