2016-11-21 5 views
1

Der Grund, warum ich frage, ist, dass in verschiedenen Datenstrukturen, dict, Liste, Zeichenfolge integriert.Jeder Weg, um diese For-Schleife mit Listenverständnis zu konvertieren?

bffer = "" 
dict_size = 128 
for character in string: 
    appnd_bffer = bffer + character 
    if appnd_bffer in codebook: 
     bffer = appnd_bffer 
    else: 
     output_list.append(codebook[bffer]) 
     codebook[appnd_bffer] = dict_size 
     dict_size += 1 
     bffer = character 

Ich bin neu auf Listen Comprehensions, so dass ich wirklich eine Erklärung verwenden könnte, wenn es möglich ist. Prost.

+8

Warum muss dieses in ein Listenverständnis konvertiert werden? Das würde die Lesbarkeit wirklich verletzen. –

+0

Warum möchten Sie? Wenn es nach einem teuflischen Voodoo möglich wäre, all das in ein Listenverständnis zu stecken, wäre es völlig unlesbar. –

+0

'[do_everything_youre_doing_in_the_loop (Zeichen) für Zeichen in String]' ...? Dies ist zu viel Code, um in ein Verständnis zu inline ... – deceze

Antwort

6

Nur um Ihnen eine Vorstellung davon zu geben, warum es eine wirklich schlechte Idee ist, Ihre LZW-Kompressor-Schleife in ein Listenverständnis zu stopfen, habe ich tatsächlich weitergemacht und etwas verrückten Code geschrieben, der genau das tut.

Es verwendet einige ziemlich zwielichtige Tricks, und es wird nicht auf Python 3 arbeiten, weil in Python 3 ein Listenverständnis in seinem eigenen Geltungsbereich läuft; In Python 2 läuft ein Listenverständnis im Umfang des umgebenden Codes. Und das bedeutet, dass mein Trick, den ursprünglichen Puffer in die List-Comp zu übergeben, in Python 3 nicht funktioniert.

Erstens, hier ist Ihr ursprünglicher Code in eine Funktion eingewickelt, mit ein paar Variablennamenänderungen und ein paar hinzugefügt Extras, um es zu einem lauffähigen, testbaren Beispiel zu machen.

from __future__ import print_function 

def lzw_compress_Boa(data): 
    dict_size = 128 
    codebook = {chr(i): i for i in range(dict_size)} 

    output_list = [] 
    oldbuff = "" 
    for ch in data: 
     newbuff = oldbuff + ch 
     if newbuff in codebook: 
      oldbuff = newbuff 
     else: 
      output_list.append(codebook[oldbuff]) 
      codebook[newbuff] = dict_size 
      dict_size += 1 
      oldbuff = ch 
    return output_list 

data = 'this data is this data' 

output_list = lzw_compress_Boa(data) 
print(output_list) 
print(len(data), '->', len(output_list)) 

Ausgang

[116, 104, 105, 115, 32, 100, 97, 116, 97, 32, 130, 32, 128, 138, 133] 
22 -> 15 

Wir eigentlich nicht brauchen, um das Codebuch der Größe in einer separaten Variable zu halten. Wie bei allen integrierten Python-Containertypen überwacht ein Diktat seine Größe, und wir können die Funktion len() verwenden, um sie zu erhalten. So können wir diese zwei Zeilen ersetzen:

codebook[newbuff] = dict_size 
dict_size += 1 

mit dieser Zeile:

codebook[newbuff] = len(codebook) 

Jetzt ist hier die verrückte Version, die eine Liste Verständnis verwendet. Denken Sie daran, Kinder, bittenicht versuchen Sie dies zu Hause! :)

Beachten Sie, dass diese Version nicht nur schwieriger zu lesen ist als die erste, die ich gepostet habe, sie ist auch weniger effizient.Und wie ich zu Beginn sagte, ist es weniger portabel, und es verwendet einige total zwielichtige Tricks, die niemals in ernstem Code verwendet werden sollten.

Listenübersichten sind cool, und wenn Sie einmal daran gewöhnt sind, können sie Ihren Code prägnanter machen, was die Lesbarkeit verbessern kann, solange Sie nicht zu viel in ihnen machen. Eine Liste comp leicht effiziente als entsprechender Code .append in einer „traditionellen“ Stil for-Schleife, aber sie sind keine Zauberei, und mit einem unverständlichen Liste Verständnis statt über eine schöne klar lesbar traditionelle for Schleife ist nicht Pythonic .

+0

Faul. Ich möchte '[b für b in Popen sehen (['working_c_implementation'], stdin = PIPE, stdout = PIPE) .communicate (Daten) [0]]'. –

+0

@ZeroPiraeus LOL. Ich wollte den Staat in einer iterierbaren Klasse halten, entschied mich jedoch, nicht zu verrückt zu werden. :) –

2

Nein, dies kann nicht zu einem Listenverständnis gemacht werden, weil es andere Ausdrücke als die enthält, aus denen die Liste besteht (z. B. dict_size += 1). Diese Ausdrücke haben einfach keinen Platz in einem Listenverständnis, da der einzige Zweck eines Verständnisses darin besteht, dieses Objekt zu erzeugen. Was Ihnen helfen könnte, ist, eine separate Funktion zu erstellen, die die Logik für eine einzelne Iteration der Schleife enthält, und diese Funktion dann in einer Schleife zu verwenden.

+1

Es kann immer noch getan werden. Es wird jedoch nicht lesbar sein. Der 'dict_size'-Wert könnte beispielsweise durch ein' itertools.count() '-Objekt behandelt werden. –

+0

Vielen Dank für die Antwort. Schnelle Frage, würde eine Funktion hinzufügen und tun, was Sie sagten, eine positive Änderung des Codes sein? Entweder in Bezug auf Lesbarkeit/"Sauberkeit"? – Boa

+0

@Boa Ja, es ist in der Regel eine gute Übung, aber hängt im Allgemeinen von Ihrer spezifischen Situation ab. – Noah

8

Die Schleife hängt derzeit davon ab, bffer zuweisen zu können. Da die Zuweisung eine Anweisung ist, und List Comprehensions nur Ausdrücken enthalten kann, würde die Umwandlung in ein Listenverständnis eine Menge schwer zu verfolgende Tricks mit veränderbaren Objekten erfordern.

Als solches würde das Konvertieren in ein Listenverständnis zu einem unlesbaren Durcheinander ohne eindeutige Vorteile führen (jegliche Geschwindigkeitsvorteile beim Entfernen des list.append() Aufrufs werden durch die veränderbaren Objektmanipulationen ausgeglichen).

+1

Hat jemand das offensichtliche Wortspiel über * Unverständlichkeit * schon gemacht ...? – deceze

+1

@deceze: Ich habe versucht, es zu vermeiden! :-D –

+0

Aus Neugier, könnte ich ein umfassendes Beispiel sehen? Ich glaube nicht, dass dies möglich war – Noah

Verwandte Themen