Ora so che non è sicuro modificare l'elenco durante un ciclo iterativo. Tuttavia, supponiamo di avere un elenco di stringhe e di voler rimuovere le stringhe stesse. La sostituzione di valori mutabili conta come modifica?
Ora so che non è sicuro modificare l'elenco durante un ciclo iterativo. Tuttavia, supponiamo di avere un elenco di stringhe e di voler rimuovere le stringhe stesse. La sostituzione di valori mutabili conta come modifica?
Risposte:
È considerata forma scadente. Utilizzare invece una comprensione dell'elenco, con assegnazione delle sezioni se è necessario conservare i riferimenti esistenti all'elenco.
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
print bviene eseguita l' istruzione, puoi dire se è astata modificata sul posto anziché sostituita. Un'altra possibilità sarebbe stata quella print b is adi vedere se entrambi si riferiscono ancora allo stesso oggetto.
Poiché il ciclo seguente modifica solo gli elementi già visti, sarebbe considerato accettabile:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
Che è diverso da:
a[:] = [s.strip() for s in a]
in quanto non richiede la creazione di un elenco temporaneo e una sua assegnazione per sostituire l'originale, sebbene richieda più operazioni di indicizzazione.
Attenzione: sebbene sia possibile modificare le voci in questo modo, non è possibile modificare il numero di elementi nel listsenza rischiare la possibilità di riscontrare problemi.
Ecco un esempio di ciò che intendo: eliminare una voce incasina l'indicizzazione da quel punto in poi:
b = ['a', ' b', 'c ', ' d ']
for i, s in enumerate(b):
if s.strip() != b[i]: # leading or trailing whitespace?
del b[i]
print(b) # -> ['a', 'c '] # WRONG!
(Il risultato è sbagliato perché non ha eliminato tutti gli elementi che dovrebbe avere.)
Aggiornare
Poiché questa è una risposta abbastanza popolare, ecco come eliminare efficacemente le voci "sul posto" (anche se non è esattamente la domanda):
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
for i in a? Questo è molto controintuitivo, apparentemente diverso dalle altre lingue e ha provocato errori nel mio codice che ho dovuto eseguire il debug per un lungo periodo di tempo. Python Tutorial non ne parla nemmeno. Anche se ci deve essere qualche motivo?
a[i]e s) per lo stesso oggetto nella stessa riga quando non è necessario? Preferirei di gran lunga fare a[i] = a[i].strip().
a[i] = s.strip()esegue una sola operazione di indicizzazione.
enumerate(b)esegue un'operazione di indicizzazione su ogni iterazione e ne stai facendo un'altra a[i] =. AFAIK è impossibile implementare questo loop in Python con solo 1 operazione di indicizzazione per iterazione di loop :(
Un altro per la variante loop, mi sembra più pulito di uno con enumerate ():
for idx in range(len(list)):
list[idx]=... # set a new value
# some other code which doesn't let you use a list comprehension
range(len(list))in Python un odore di codice.
enumerateè un generatore non crea un elenco di tuple, le crea una alla volta mentre scorre l'elenco. L'unico modo per dire quale è più lento sarebbe timeit.
La modifica di ogni elemento durante l'iterazione di un elenco va bene, a condizione che non si cambi aggiungere / rimuovere elementi all'elenco.
È possibile utilizzare la comprensione dell'elenco:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
o fai semplicemente il C-styleciclo for:
for index, item in enumerate(l):
l[index] = item.strip()
No, non altereresti il "contenuto" dell'elenco, se potessi mutare le stringhe in quel modo. Ma in Python non sono mutabili. Qualsiasi operazione su stringa restituisce una nuova stringa.
Se avessi un elenco di oggetti che sapevi fossero mutabili, potresti farlo purché non modifichi il contenuto effettivo dell'elenco.
Quindi dovrai fare una mappa di qualche tipo. Se si utilizza un'espressione del generatore, l'operazione [l'operazione] verrà eseguita mentre si esegue l'iterazione e si risparmierà memoria.
La risposta data da Jemshit Iskenderov e Ignacio Vazquez-Abrams è davvero buona. Può essere ulteriormente illustrato con questo esempio: immaginalo
a) ti viene fornito un elenco con due vettori;
b) si desidera attraversare l'elenco e invertire l'ordine di ciascuna delle matrici
Diciamo che hai
v = np.array([1, 2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i = i[::-1] # this command does not reverse the string
print([v,b])
Otterrete
[array([1, 2, 3, 4]), array([3, 4, 6])]
D'altra parte, se lo fai
v = np.array([1, 2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i[:] = i[::-1] # this command reverses the string
print([v,b])
Il risultato è
[array([4, 3, 2, 1]), array([6, 4, 3])]
Dalla tua domanda non è chiaro quali siano i criteri per decidere quali stringhe rimuovere, ma se hai o puoi fare un elenco delle stringhe che desideri rimuovere, puoi fare quanto segue:
my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
for i in range(my_strings.count(undesirable_string)):
my_strings.remove(undesirable_string)
che cambia my_strings in ['a', 'c', 'e']
In breve, per apportare modifiche all'elenco durante l'iterazione dello stesso elenco.
list[:] = ["Modify the list" for each_element in list "Condition Check"]
esempio:
list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]