Porównanie wielu list Python

Sep 17 2020

Mam kod, który ma trzy listy, a następnie sprawdza indeks drugiej listy względem indeksu pierwszej, o ile pierwsza lista ma sześć elementów. Kod zostanie następnie dołączony do trzeciej listy, jeśli część ciągu pasuje do indeksu pierwszej listy. Jeśli ciąg nie pasuje, dołączy wiadomość. Mam nadzieję, że znajdę lepszy, bardziej Pythonowy sposób pisania mojego algorytmu. Oto mój kod:

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

Ten kod działa zgodnie z tym, co chcę, ale myślę, że jest za długi. Każda pomoc w uczynieniu tego kodu bardziej Pythonic będzie bardzo mile widziana. Z góry dziękuję.

Odpowiedzi

2 FMc Sep 18 2020 at 00:11

Moją recenzję twojego obecnego kodu łatwo podsumować: jest cholernie skomplikowany i boli mnie głowa . Ale nie czuj się źle, bo jesteś w świetnym towarzystwie. Często takie są pierwsze próby - nawet dla osób, które robią to od dłuższego czasu.

Co konkretnie utrudnia zrozumienie? Złożoność algorytmiczna: zagnieżdżone pętle i instrukcje warunkowe, przerwy, zarządzanie indeksami list i tak dalej. Ilekroć dostrzegasz tego rodzaju złożoność, często warto zastanowić się, czy potężniejsza struktura danych uprościłaby sytuację (używam „struktury danych” w bardzo szerokim znaczeniu). W poniższym przepisaniu użyjemy specjalnej iteracji, która pozwoli nam zerknąć na następną wartość bez faktycznego jej zużywania za każdym razem. Ta jedna zmiana drastycznie upraszcza prowadzenie ksiąg w głównej pętli, a także upraszcza sposób, w jaki dodajemy resztę brakujących wartości po wyjściu z pętli.

# 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

Ponieważ continuezawsze dzieje się na końcu pętli, możesz odwrócić te warunki, aby ją skrócić.

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

teraz nie potrzebujesz, elseponieważ cokolwiek innego niż stan zerwania będzie continueautomatycznie.

Wyżej, gdzie się usiadłeś cont = False, możesz użyć breakzamiast tego, o ile wiem. To contcałkowicie eliminuje potrzebę, więc możesz to zrobićwhile True:

GáborFekete Sep 17 2020 at 23:37

Odpowiadam głównie na SO, więc moja odpowiedź może nie być zgodna z PEP8 lub innymi wytycznymi, ale próbowałem stworzyć wersję twojego kodu, która będzie łatwiejsza do zobaczenia, bez ifs, break, kontynuacji i mającej mniejszą liczbę linii:

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