Comparaison de listes multiples Python

Sep 17 2020

J'ai un code qui a trois listes, et il vérifie ensuite l'index de la deuxième liste par rapport à l'index de la première tant que la première liste a six éléments. Le code s'ajoutera alors à la troisième liste si une partie d'une chaîne correspond à l'index de la première liste. Si la chaîne ne correspond pas, il ajoutera un message. J'espère trouver une manière meilleure et plus pythonique d'écrire mon algorithme. Voici mon code:

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

Ce code fonctionne pour ce que je veux qu'il fasse mais je pense que c'est trop long. Toute aide pour rendre ce code plus pythonique serait grandement appréciée. Merci d'avance.

Réponses

2 FMc Sep 18 2020 at 00:11

Mon examen de votre code actuel est facile à résumer: c'est sacrément compliqué et cela me fait mal à la tête . Mais ne vous sentez pas mal, car vous êtes en bonne compagnie. Les premières tentatives sont souvent comme ça - même pour les personnes qui font cela depuis longtemps.

Qu'est-ce qui rend difficile la compréhension? Complexité algorithmique: boucles imbriquées et conditionnelles, ruptures, gestion des index de liste, etc. Chaque fois que vous percevez ce type de complexité, il est souvent utile de se demander si une structure de données plus puissante simplifierait la situation (j'utilise la «structure de données» dans un sens très large). Dans la réécriture proposée ci-dessous, nous utiliserons un itérable spécial qui nous permet de jeter un œil à la valeur suivante sans la consommer à chaque fois. Ce changement simplifie considérablement la comptabilité dans la boucle principale et simplifie également la façon dont nous ajoutons le reste nécessaire des valeurs manquantes après la sortie de la boucle.

# 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

Comme continuecela se produit toujours à la fin d'une boucle, vous pouvez inverser ces conditions, pour la raccourcir.

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

maintenant, vous n'avez pas besoin de elserien d'autre que la condition de rupture continue.

Plus haut là où vous vous placez cont = False, vous pouvez utiliser à la breakplace pour autant que je sache. Cela supprime contcomplètement le besoin de fairewhile True:

GáborFekete Sep 17 2020 at 23:37

Je réponds principalement sur SO, donc ma réponse ne suit peut-être pas PEP8 ou d'autres directives, mais j'ai essayé de créer une version de votre code qui soit plus facile à voir ce qui se passe, sans si, sans interruption, continue et avec un nombre de lignes plus petit:

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