Python de comparación de listas múltiples

Sep 17 2020

Tengo un código que tiene tres listas y luego verifica el índice de la segunda lista con el índice de la primera siempre que la primera lista tenga seis elementos. El código luego se agregará a la tercera lista si parte de una cadena coincide con el índice de la primera lista. Si la cadena no coincide, agregará un mensaje. Espero encontrar una forma mejor y más pitónica de escribir mi algoritmo. Aquí está mi código:

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

Este código funciona para lo que quiero que haga, pero creo que es demasiado largo. Cualquier ayuda para hacer este código más Pythonic será muy apreciada. Gracias por adelantado.

Respuestas

2 FMc Sep 18 2020 at 00:11

Mi revisión de su código actual es fácil de resumir: es demasiado complicado y me duele la cabeza . Pero no te sientas mal, porque estás en buena compañía. Los primeros intentos suelen ser así, incluso para personas que han estado haciendo esto durante mucho tiempo.

¿Qué, específicamente, lo hace difícil de entender? Complejidad algorítmica: bucles anidados y condicionales, rupturas, gestión de índices de listas, etc. Siempre que perciba ese tipo de complejidad, a menudo ayuda considerar si una estructura de datos más poderosa simplificaría la situación (estoy usando "estructura de datos" en un sentido muy amplio). En la reescritura que se ofrece a continuación, utilizaremos un iterable especial que nos permite echar un vistazo al siguiente valor sin consumirlo cada vez. Ese cambio simplifica drásticamente la contabilidad dentro del ciclo principal, y también simplifica la forma en que agregamos el resto necesario de los valores faltantes después de salir del 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

Dado que continuesiempre ocurre al final de un ciclo, puede revertir estas condiciones para acortarlo.

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

ahora no lo necesita elseya que nada más que la condición de ruptura lo hará continueautomáticamente.

Más arriba donde se establezca cont = False, podría usar breaken su lugar, por lo que puedo decir. Eso elimina por contcompleto la necesidad de hacerwhile True:

GáborFekete Sep 17 2020 at 23:37

Estoy respondiendo principalmente en SO, por lo que es posible que mi respuesta no esté siguiendo PEP8 u otras pautas, pero intenté hacer una versión de su código que sea más fácil de ver lo que está sucediendo, sin ifs, interrupciones, continúa y con un recuento de líneas más pequeño:

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