repeated - python duplicate
Python: Renombra los duplicados en la lista con nĂºmeros progresivos sin ordenar la lista (6)
Dada una lista como esta:
mylist = ["name", "state", "name", "city", "name", "zip", "zip"]
Me gustaría cambiar el nombre de los duplicados agregando un número para obtener el siguiente resultado:
mylist = ["name1", "state", "name2", "city", "name3", "zip1", "zip2"]
No quiero cambiar el orden de la lista original. Las soluciones sugeridas para esta pregunta relacionada sobre el desbordamiento de pila ordenan la lista, lo que no quiero hacer.
Aquí hay una solución O(n)
muy simple. Simplemente recorra la lista almacenando el índice del elemento en la lista. Si hemos visto este elemento anteriormente, use los datos almacenados anteriormente para agregar el valor de ocurrencia.
Este enfoque resuelve el problema con solo crear un diccionario más para mirar hacia atrás. Evita hacer mirar hacia adelante para que no creamos segmentos de listas temporales.
mylist = ["name", "state", "name", "city", "city", "name", "zip", "zip", "name"]
dups = {}
for i, val in enumerate(mylist):
if val not in dups:
# Store index of first occurrence and occurrence value
dups[val] = [i, 1]
else:
# Special case for first occurrence
if dups[val][1] == 1:
mylist[dups[val][0]] += str(dups[val][1])
# Increment occurrence value, index value doesn''t matter anymore
dups[val][1] += 1
# Use stored occurrence value
mylist[i] += str(dups[val][1])
print mylist
# [''name1'', ''state'', ''name2'', ''city1'', ''city2'', ''name3'', ''zip1'', ''zip2'', ''name4'']
Así es como lo haría.
mylist = ["name", "state", "name", "city", "name", "zip", "zip"]
from collections import Counter # Counter counts the number of occurrences of each item
counts = Counter(mylist) # so we have: {''name'':3, ''state'':1, ''city'':1, ''zip'':2}
for s,num in counts.items():
if num > 1: # ignore strings that only appear once
for suffix in range(1, num + 1): # suffix starts at 1 and increases by 1 each time
mylist[mylist.index(s)] = s + str(suffix) # replace each appearance of s
EDITAR: Aquí está en una sola línea, sin embargo, el orden no se conserva.
[s + str(suffix) if num>1 else s for s,num in Counter(mylist).items() for suffix in range(1, num+1)]
# Produces: [''zip1'', ''zip2'', ''city'', ''state'', ''name1'', ''name2'', ''name3'']
Cualquier método en el que se llame a count
en cada elemento dará como resultado O(n^2)
ya que count
es O(n)
. Puedes hacer algo como esto:
# not modifying original list
from collections import Counter
mylist = ["name", "state", "name", "city", "name", "zip", "zip"]
counts = {k:v for k,v in Counter(mylist).items() if v > 1}
newlist = mylist[:]
for i in reversed(range(len(mylist))):
item = mylist[i]
if item in counts and counts[item]:
newlist[i] += str(counts[item])
counts[item]-=1
print(newlist)
# [''name1'', ''state'', ''name2'', ''city'', ''name3'', ''zip1'', ''zip2'']
# modifying original list
from collections import Counter
mylist = ["name", "state", "name", "city", "name", "zip", "zip"]
counts = {k:v for k,v in Counter(mylist).items() if v > 1}
for i in reversed(range(len(mylist))):
item = mylist[i]
if item in counts and counts[item]:
mylist[i] += str(counts[item])
counts[item]-=1
print(mylist)
# [''name1'', ''state'', ''name2'', ''city'', ''name3'', ''zip1'', ''zip2'']
Esto debería ser O(n)
.
Otras respuestas proporcionadas:
mylist.index(s)
por elemento causa O(n^2)
mylist = ["name", "state", "name", "city", "name", "zip", "zip"]
from collections import Counter
counts = Counter(mylist)
for s,num in counts.items():
if num > 1:
for suffix in range(1, num + 1):
mylist[mylist.index(s)] = s + str(suffix)
count(x[1])
por elemento causa O(n^2)
También se usa varias veces por elemento junto con el corte de lista.
print map(lambda x: x[1] + str(mylist[:x[0]].count(x[1]) + 1) if mylist.count(x[1]) > 1 else x[1], enumerate(mylist))
Puntos de referencia:
Menos cosas de lujo.
from collections import defaultdict
mylist = ["name", "state", "name", "city", "name", "zip", "zip"]
finalList = []
dictCount = defaultdict(int)
anotherDict = defaultdict(int)
for t in mylist:
anotherDict[t] += 1
for m in mylist:
dictCount[m] += 1
if anotherDict[m] > 1:
finalList.append(str(m)+str(dictCount[m]))
else:
finalList.append(m)
print finalList
Mi solución con map
y lambda
:
print map(lambda x: x[1] + str(mylist[:x[0]].count(x[1]) + 1) if mylist.count(x[1]) > 1 else x[1], enumerate(mylist))
Forma mas tradicional
newlist = []
for i, v in enumerate(mylist):
totalcount = mylist.count(v)
count = mylist[:i].count(v)
newlist.append(v + str(count + 1) if totalcount > 1 else v)
Y el ultimo
[v + str(mylist[:i].count(v) + 1) if mylist.count(v) > 1 else v for i, v in enumerate(mylist)]
Puedes usar la tabla hash para resolver este problema. Definir un diccionario d. clave es la cadena y el valor es (first_time_index_in_the_list, times_of_appearance). Cada vez que vea una palabra, solo verifique el diccionario, y si el valor es 2, use first_time_index_in_the_list para agregar ''1'' al primer elemento, y agregue times_of_appearance al elemento actual. Si es mayor que 2, simplemente agregue times_of_appearance al elemento actual.