Topic: Rimozione doppi caratteri stringa  (Letto 171 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline gila75

  • python unicellularis
  • *
  • Post: 8
  • Punti reputazione: 0
    • Mostra profilo
Rimozione doppi caratteri stringa
« il: Settembre 09, 2019, 20:42 »
Ciao a tutti, sono nuovo, mi sono presentato nella apposita sezione.
é da tempo che cerco d'imparare Python, ma per un motivo o l'altro mi sono sempre arenato. Ora sembrerebbe essere la volta buona.
Come detto, sono alle prime armi quindi abbiate pazienza.
Sto facendo i soliti esercizi da principiante, in questo caso, uno script che rimuova i caratteri doppi in una stringa:
str='casa xx 1123"------> 'cas x123'

Ho trovato 2 modi e vorrei sapere quale dei due è più pitonico come si suol dire.
Primo modo: sfrutta la propietà degli insiemi che eliminano i "doppioni", ma non mantengono al pari dei dizionari l'ordine (a volte si a volte no)
#elimina i caratteri doppi


old_str='xxxxxxxxxxxxxxxxx 123     56'
new_str=''
s=set(old_str)
for i in old_str:
if i in s:
new_str+=i
s.remove(i)
print (new_str)

''' OUTPUT:
gila@gila-pc:~/Scrivania$ python3 x.py
x 12356
'''

con un piccolo stratagemma posso ricostruire l'ordine della stringa iniziale.

Secondo metodo (per me migliore, ma più adatto forse ad altri linguaggi)
l=[0]*500
old_str='1111122222casa     gino èèèèùùùùçç@@@'
new_str=''
for i in old_str:
if l[ord(i)]==0:
new_str+=i
l[ord(i)]=1
print (new_str)


''' OUTPUT:
gila@gila-pc:~/Scrivania$ python3 x.py
12cas ginoèùç@''''


Questa tecnica marca ad 1 l'elemento della lista del corrispettivo carattere es:a=97 (codice ascii).
Se è a zero stampa, se è a 1 significa che è un doppione.
Ci sarebbe un terzo metodo, simile al secondo (lista marcata) che fa risparmiare un bel po' di memoria, ma sfrutta i bit e gli operatori a basso livello (and, or) ecc...
e non mi pare il caso per un linguaggio come Python.
Mi farebbe piacere un vostro consiglio su quale metodo è più consono per Python.
Grazie a tutti in anticipo  :)

Offline nuzzopippo

  • python habilis
  • **
  • Post: 60
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #1 il: Settembre 10, 2019, 10:48 »
Ciao @gila

 ... come al solito mi affascina vedere schemi di pensiero diversi dai miei, in particolare il metodo con lista marcata non lo avrei mai pensato, lo devo guardar bene per capire la tecnica ;)

Lungi da me l'idea indicare metodi "più pythonici" che delego ai molti utenti più capaci che ci sono in giro, se interessati a rispondere, io avrei più banalmente fatto :
>>> def uni_car(old_str):
tmp = []
for i in range(len(old_str)):
if not old_str[i] in tmp:
tmp.append(old_str[i])
return ''.join(tmp)

>>> uni_car('casa xx 1123')
'cas x123'
>>> uni_car('xxxxxxxxxxxxxxxxx 123     56')
'x 12356'
>>> uni_car('1111122222casa     gino èèèèùùùùçç@@@')
'12cas ginoèùç@'
>>>


... il codice della funzione da me proposta si presterebbe, con piccole variazioni, anche alla eliminazione dei soli caratteri "consecutivamente uguali",  in questo modo:
>>> def cons_car(old_str):
tmp = []
for i in range(len(old_str) - 1):
if old_str[i] != old_str[i+1]:
tmp.append(old_str[i])
tmp.append(old_str[-1])
return ''.join(tmp)

>>> cons_car('casa xx 1123')
'casa x 123'
>>> cons_car('xxxxxxxxxxxxxxxxx 123     56')
'x 123 56'
>>> cons_car('1111122222casa     gino èèèèùùùùçç@@@')
'12casa gino èùç@'
>>>

Offline gila75

  • python unicellularis
  • *
  • Post: 8
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #2 il: Settembre 11, 2019, 16:28 »
Grazie Nuzzo. Io invece non avrei pensato il tuo modo. Mi sembra snello e performante. Il metodo della lista marcata, come ho detto forse e' piu per altri linguaggi.
Vediamo se qualcuno ha altri metodi.
Edit: riflettento, mi sembra molto migliore il tuo approccio rispetto al mio che usa gli insiemi.
« Ultima modifica: Settembre 11, 2019, 16:38 da gila75 »

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:Rimozione doppi caratteri stringa
« Risposta #3 il: Settembre 11, 2019, 23:16 »
Ciao, Se non ti interessa l'ordine la soluzione piu' pythonica e':
>>> s = "afdasdf"
>>> set(s)
{'d', 'a', 's', 'f'}


Se invece vuoi mantenere l'ordine, possiamo trovare altre soluzioni.

Offline gila75

  • python unicellularis
  • *
  • Post: 8
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #4 il: Settembre 12, 2019, 20:08 »


Se invece vuoi mantenere l'ordine, possiamo trovare altre soluzioni.

Si, sarebbe interessante per me come esercizio base vedere più strade.
Contrariamente a quanto avrei immaginato la mia soluzione con lista marcata è poco efficiente, molto più veloce la soluzione di @Nuzzo o quella che sfrutta set()
Vuol dire che è altamente ottimizzata allora set...credo.
Comunque si  @bebo o @nuzzo o altri...se ci sono altre strade ben venga. Intanto proseguo con lo studio

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:Rimozione doppi caratteri stringa
« Risposta #5 il: Settembre 13, 2019, 10:09 »
Se vuoi guardare le prestazioni, considera anche che set() e' scritto in C sotto, mentre il tuo algoritmo e' in python.

Se vuoi mantenere l'ordine:
>>> from collections import OrderedDict
>>> s = "asdfdadsfafagda"
>>> d = OrderedDict.fromkeys(s)
>>> d
OrderedDict([('a', None), ('s', None), ('d', None), ('f', None), ('g', None)])
>>> "".join(d)
'asdfg'


Preso da: https://stackoverflow.com/questions/9841303/removing-duplicate-characters-from-a-string

Se vuoi un consiglio per imparare: pensa prima alle strutture dati, e poi agli algoritmi.

Offline gila75

  • python unicellularis
  • *
  • Post: 8
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #6 il: Settembre 13, 2019, 18:08 »
Certamente @bebo, ma sono solo piccoli programmi per fissare cio' che ho studiato  fin ora.
Ah....mi pareva, set() e' veramente velocissima...chissa' come e' stata scritta, sarei curioso visto che "vengo" dal C. 
Purtroppo ora non ho sotto mano il pc per provare lo script da te proposto, intanto me lo guardo, grazie!

Offline nuzzopippo

  • python habilis
  • **
  • Post: 60
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #7 il: Settembre 14, 2019, 10:42 »
beh ... set() era stato usato nel primo esempio posto, mi sembrava evidente si volesse un elenco "indicizzato" dei caratteri.

Per altro, ho trovato molto "intrigante" il link proposto da @bebo, in particolare, sempre sotto l'aspetto "carattere unico indicizzato" il metodo:
>>> var = '1111122222casa     gino èèèèùùùùçç@@@'
>>> ''.join(sorted(set(var), key=var.index))
'12cas ginoèùç@'
>>>

per il quale possedevo tutte le nozioni necessarie ma che non mi ha sfiorato la mente ma anche altre soluzioni sono "interessanti".

 ... l'utilità di fondo di tal genere di discussioni : aprono gli occhi :)

Offline gila75

  • python unicellularis
  • *
  • Post: 8
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #8 il: Settembre 15, 2019, 18:47 »
Grazie ragazzi, appena ho tempo studio le 2 ultime soluzioni. Non sono sicuro di aver studiato ancora alcune cose, ma nel caso le metto in "cascina" e le tengo per
il futuro.
E si Nuzzo, a volte da banalità saltano fuori idee di altri, che nemmeno ti sogneresti.

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:Rimozione doppi caratteri stringa
« Risposta #9 il: Settembre 16, 2019, 10:30 »
beh ... set() era stato usato nel primo esempio posto, mi sembrava evidente si volesse un elenco "indicizzato" dei caratteri.

Per altro, ho trovato molto "intrigante" il link proposto da @bebo, in particolare, sempre sotto l'aspetto "carattere unico indicizzato" il metodo:
>>> var = '1111122222casa     gino èèèèùùùùçç@@@'
>>> ''.join(sorted(set(var), key=var.index))
'12cas ginoèùç@'
>>>


Pero' qua tu stai ri-ordinando la stringa finale con un ordinamento che potrebbe essere diverso dall'ordine originale.

Ossia, due stringhe in input con caratteri ordinati differentemente producono lo stesso output:
>>> var = '1111122222casa     gino èèèèùùùùçç@@@'
>>> ''.join(sorted(set(var), key=var.index))
'12cas ginoèùç@'

>>> var2 = '22222casa11     gino èèèèùùùùçç@@@'
>>> ''.join(sorted(set(var2), key=var.index))
'12cas ginoèùç@'
« Ultima modifica: Settembre 16, 2019, 10:32 da bebo »

Offline nuzzopippo

  • python habilis
  • **
  • Post: 60
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #10 il: Settembre 16, 2019, 15:35 »
Pero' qua tu stai ri-ordinando la stringa finale con un ordinamento che potrebbe essere diverso dall'ordine originale.

Ossia, due stringhe in input con caratteri ordinati differentemente producono lo stesso output:
>>> var = '1111122222casa     gino èèèèùùùùçç@@@'
>>> ''.join(sorted(set(var), key=var.index))
'12cas ginoèùç@'

>>> var2 = '22222casa11     gino èèèèùùùùçç@@@'
>>> ''.join(sorted(set(var2), key=var.index))
'12cas ginoèùç@'


@bebo, ritengo l'intervento in citazione una svista, dato che è banale che volendo mantenere l'ordinamento di una variabile sarà l'indice di quest'ultima e non di un'altra la chiave di ordinamento.
In tal senso l'esempio in citazione avrebbe dovuto essere :
>>> var = '1111122222casa     gino èèèèùùùùçç@@@'
>>> ''.join(sorted(set(var), key=var.index))
'12cas ginoèùç@'
>>> var2 = '22222casa11     gino èèèèùùùùçç@@@'
>>> ''.join(sorted(set(var2), key=var2.index))
'2cas1 ginoèùç@'
>>>


Ovviamente, è possibile Tu intenda qualcos'altro che non ho compreso, in tal caso sono tutto orecchi

Offline gila75

  • python unicellularis
  • *
  • Post: 8
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #11 il: Settembre 16, 2019, 18:26 »
Interessante la soluzione che usa  OrderedDict.fromkeys(s) . Logicamente come immaginerete, essendo agli inizi non la conosco.
Sono uscite idee, che ho prontamente salvato, e ho fatto tesoro.
Piccola divagazione, ma in questo contesto, penso siano troppo e forse inutili, apro e chiudo per non andare ot.
Per operazioni di parsing più avanzate (rispetto alla semplice eliminazione di caratteri doppi), trovavo formidabile senza impazzire a suon di if,
gli automi a stati finiti. Non so se in python esistono già "preconfezionati", io li avevo implementati in C. ma ora lasciamo perdere.
per quanto mi riguarda, siete stati molto esaustivi e mi ritengo soddisfatto, grazie !!

EDIT:
non capisco però questa riga di codice:
>>> ''.join(sorted(set(var), key=var.index))


forse l'ho studiato , ma in questo contesto non capisco  "key=var.index
so che per esempio str.index('s'), mi restituisce la posizione di 's' se esiste, ma qui non capisco bene... non ci sono argomenti.
Presumo allora sia l'indirizzo d'inizio stringa.
Potreste spiegarmi ?

« Ultima modifica: Settembre 16, 2019, 20:44 da gila75 »

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:Rimozione doppi caratteri stringa
« Risposta #12 il: Settembre 17, 2019, 00:30 »
@bebo, ritengo l'intervento in citazione una svista
Corretto, stavo giochicchiando con la tua soluzione e non mi sono accorto di non aver aggiornato la seconda variabile. Grazie.

Offline nuzzopippo

  • python habilis
  • **
  • Post: 60
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #13 il: Settembre 17, 2019, 09:49 »
...
non capisco però questa riga di codice:
>>> ''.join(sorted(set(var), key=var.index))

...Presumo allora sia l'indirizzo d'inizio stringa.
Potreste spiegarmi ?

Pur con tutti i dubbi derivanti dalla mia ignoranza dell'inglese, cercherò di spiegare quello che ho capito io.
la funzione builtin "sorted" ha vari parametri possibili :
>>> help('sorted')
Help on built-in function sorted in module builtins:

sorted(iterable, /, *, key=None, reverse=False)
    Return a new list containing all items from the iterable in ascending order.
   
    A custom key function can be supplied to customize the sort order, and the
    reverse flag can be set to request the result in descending order.

>>>

in particolare, il parametro, non obbligatorio, key definisce una funzione da utilizzarsi per ordinare gli elementi dell'oggetto iterabile passato quale primo parametro.
Nello specifico, il metodo index delle stringhe che restituisce la posizione del singolo carattere nella stringa da utilizzarsi quale criterio di ordinamento.
[Edit]Avevo omesso di dirlo : ovviamento è sorted che si fa carico di applicare la funzione ai singoli elementi dello iterabile, definendone l'ordine.
Nel caso di 'str.index(substr)' è il primo apparire del caattere nella stringa, il che va benissimo nel caso in esame[/Edit]
Quando omesso, vengono utilizzati i metodi standard previsti per l'oggetto da esaminarsi (p.e., alfabetico per oggetti stringa) ammesso che l'oggetto lo definisca,

Ne consegue che non necessariamente l'ordinamento risultante sia quello canonico per l'oggetto in esame, p.e. supposta una lista di stringhe :
>>> lista = ['d', 'ccc', 'aaa', 'bbbb', 'ee']
>>> sorted(lista)
['aaa', 'bbbb', 'ccc', 'd', 'ee']
>>>


volendola ordinare per la lunghezza delle stringhe potremmo utilizzare la funzione bultin "len() quale chiave di ordinamento
>>> sorted(lista, key=len)
['d', 'ee', 'ccc', 'aaa', 'bbbb']
>>>

ed è anche possibile utilizzare funzioni "personalizzate".

Come detto in precedenza, non necessariamente gli elementi costituenti un iterabile, tipo una lista, possiedono un criterio di ordinamento, potrebbero essere, p.e., oggetti definiti dall'utente senza definizione di criteri di comparazione, letta la Tua domanda mi son divertito a prepararti un esempio basato sui dizionari (oltre che prematuro, temo, sarebbe lungo un esempio sugli oggetti utente), posto di avere questo elenco di nomi
Paolino;Paperino
De Paperoni;Paperone
Gastone;Paperone
De Paperis;Pico
Pitagorico;Archimede

da inserirsi in una lista di paperi
>>> import os
>>> os.chdir('/media/nuzzo/progetti/digila/sorted')
>>> paperi = []
>>> f = open('nomi', 'r')
>>> for riga in f.read().splitlines():
nome = {}
data = riga.split(';')
nome['cogn'] = data[0]
nome['nome'] = data[1]
paperi.append(nome)


>>> f.close()
>>> for elem in paperi:
print(elem)


{'cogn': 'Paolino', 'nome': 'Paperino'}
{'cogn': 'De Paperoni', 'nome': 'Paperone'}
{'cogn': 'Gastone', 'nome': 'Paperone'}
{'cogn': 'De Paperis', 'nome': 'Pico'}
{'cogn': 'Pitagorico', 'nome': 'Archimede'}
>>>

la lista sarà ordinata secondo l'ordine di inserimento, se noi volessimo "ordinarla" non potremmo farlo direttamente :
>>> sorted(paperi)
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    sorted(paperi)
TypeError: '<' not supported between instances of 'dict' and 'dict'
>>>

Perché sorted non conosce il criterio di ordinamento di una serie di dizionari, dovremmo dirglielo noi. Potremmo ordinare un dizionario per chiave o valore, una lista di dizionari non ha molto senso ordinata per chiave, diciamo che vogliamo ordinarla per valore, sia il cognome od il nome, potremmo fare :
>>> for elem in sorted(paperi, key=lambda e: e['cogn']):
print(elem)


{'cogn': 'De Paperis', 'nome': 'Pico'}
{'cogn': 'De Paperoni', 'nome': 'Paperone'}
{'cogn': 'Gastone', 'nome': 'Paperone'}
{'cogn': 'Paolino', 'nome': 'Paperino'}
{'cogn': 'Pitagorico', 'nome': 'Archimede'}
>>> for elem in sorted(paperi, key=lambda e: e['nome']):
print(elem)


{'cogn': 'Pitagorico', 'nome': 'Archimede'}
{'cogn': 'Paolino', 'nome': 'Paperino'}
{'cogn': 'De Paperoni', 'nome': 'Paperone'}
{'cogn': 'Gastone', 'nome': 'Paperone'}
{'cogn': 'De Paperis', 'nome': 'Pico'}
>>>

In questo caso ho utilizzato una funzione lambda, sono possibili altre metodologie.

Spero Ti sia sufficiente :)
« Ultima modifica: Settembre 17, 2019, 10:13 da nuzzopippo »

Offline gila75

  • python unicellularis
  • *
  • Post: 8
  • Punti reputazione: 0
    • Mostra profilo
Re:Rimozione doppi caratteri stringa
« Risposta #14 il: Settembre 17, 2019, 21:23 »
Grazie Nuzzo, sempre molto gentile e chiaro. Sorted, l'avevo letta sul manuale, ma non ricordavo l'opzione key.
Devo vedere bene l'ultimo esempio, purtroppo lo studio va un po' a rilento, faccio 9 ore al giorno e alla sera sono un po' cotto.