Confronto di liste multiple Python

Sep 17 2020

Ho un codice che ha tre elenchi, quindi controlla l'indice del secondo elenco rispetto all'indice del primo purché il primo elenco abbia sei elementi. Il codice verrà quindi aggiunto al terzo elenco se parte di una stringa corrisponde all'indice del primo elenco. Se la stringa non corrisponde, verrà aggiunto un messaggio. Spero di trovare un modo migliore e più pitonico di scrivere il mio algoritmo. Ecco il mio codice:

L1 = ["first = 1st","second = 2nd","third = 3rd","fourth = 4th","sixth = 6th",
  "first = A","second = B","third = C","fifth = E","sixth = F",
  "second = W","third = X","fourth = Y","fifth = Z","sixth = AA","first = BB"]
L2 = ["first","second","third","fourth","fifth","sixth"]
L3 = []

#Used in case a list has less than six elements
if len(L1) % 6 != 0:
    L1.append("Missing_Data")

c = 0
for i in L1:
    cont = True
    while cont:
        if L2[c] in i:
            L3.append(i.split("= ")[-1])
            c += 1
            if c < len(L2):
                cont = False
            else:
                c = 0
                cont = False
        else:
            L3.append("Missing_Data")
            c += 1
            if c < len(L2):
                continue
            else:
                c = 0
                break

Questo codice funziona per quello che voglio che faccia, ma penso che sia troppo lungo. Qualsiasi aiuto nel rendere questo codice più Pythonic sarebbe molto apprezzato. Grazie in anticipo.

Risposte

2 FMc Sep 18 2020 at 00:11

La mia revisione del tuo codice attuale è facile da riassumere: è troppo complicato e mi fa male la testa . Ma non sentirti male, perché sei in ottima compagnia. I primi tentativi sono spesso così, anche per le persone che lo fanno da molto tempo.

Cosa, nello specifico, lo rende difficile da capire? Complessità algoritmica: cicli annidati e condizionali, interruzioni, gestione degli indici di elenchi e così via. Ogni volta che percepisci quel tipo di complessità, spesso aiuta a considerare se una struttura dati più potente semplificherebbe la situazione (sto usando "struttura dati" in un senso molto ampio). Nella riscrittura offerta di seguito, utilizzeremo uno speciale iterabile che ci consente di sbirciare il valore successivo senza consumarlo effettivamente ogni volta. Quella modifica semplifica drasticamente la contabilità all'interno del ciclo principale e semplifica anche il modo in cui aggiungiamo il resto necessario dei valori mancanti dopo essere usciti dal ciclo.

# This is a third party library that is worth knowing about.
from more_itertools import peekable

# Your data, aligned so we can see what is going on.
# When you ask a question, it's a good idea to help your helpers.
xs = [
    'first = 1st', 'second = 2nd', 'third = 3rd', 'fourth = 4th',              'sixth = 6th',
    'first = A',   'second = B',   'third = C',                   'fifth = E', 'sixth = F',
                   'second = W',   'third = X',   'fourth = Y',   'fifth = Z', 'sixth = AA',
    'first = BB',
]

ys = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']

# Python has a builtin concept for missing data. Use it if you can.
# If you cannot, define a constant.
MISSING = None

# The results we want.
# When you ask a question, it's a good idea to provide this.
EXPECTED = [
    '1st',     '2nd',     '3rd',     '4th',     MISSING,   '6th',
    'A',       'B',       'C',       MISSING,   'E',       'F',
    MISSING,   'W',       'X',       'Y',       'Z',       'AA',
    'BB',      MISSING,   MISSING,   MISSING,   MISSING,   MISSING
]

# We will use a peekable iterable for both the Xs and the Ys.
xit = peekable(xs)
yit = None
results = []

# Process all Xs to build the results.
# A Y is consumed each time, and we get a fresh Ys iterable as needed.
# We consume an X only when current X and Y agree.
while xit:
    yit = yit or peekable(ys)
    x = xit.peek()
    y = next(yit)
    val = next(xit).split('= ')[-1] if y in x else MISSING
    results.append(val)

# The results should always contain a full cycle of Ys.
results.extend(MISSING for _ in yit)

# Check.
print(results == EXPECTED)
1 user985366 Sep 17 2020 at 19:46
if c < len(L2):
    continue
else:
    c = 0
    break

Dato che continueaccade sempre alla fine di un ciclo, puoi invertire queste condizioni, per renderlo più breve.

if c >= len(L2):
    c = 0
    break

ora non è necessario elsepoiché nient'altro che la condizione di interruzione verrà continueautomaticamente.

Più in alto dove ti sei ambientato cont = False, potresti usare breakinvece, per quanto posso dire. Ciò elimina la necessità di conttutto, quindi puoi semplicemente farlowhile True:

GáborFekete Sep 17 2020 at 23:37

Sto principalmente rispondendo su SO, quindi la mia risposta potrebbe non seguire PEP8 o altre linee guida, ma ho provato a creare una versione del tuo codice che sia più facile da vedere cosa sta succedendo, senza se, interruzioni, continua e con un numero di righe inferiore:

length = len(L2)
missing = 'Missing_Data'
index = -1

for item in L1:
    key,value = item.split(' = ')
    current = L2.index(key)
    no_missing = (current-index)%length-1 # get number of missing elements
    L3 += [missing] * no_missing # append this many of the missing value
    L3.append(value) # append current value
    index = current
    
L3 += [missing] * (length-index-1) # fill rest of list with missing elements