Brauche Hilfe, Verständnis Problem

Code-Stücke können hier veröffentlicht werden.
Antworten
Odox
User
Beiträge: 9
Registriert: Montag 25. Juni 2018, 19:10

Hallo Communitiy,
mein weg Python 3 zu lernen schreitet voran. Diesmal komme ich mit meiner Aufgabe, leider wieder nicht weiter.
Wenn ihr mich erleuchtet wäre ich euch sehr dankbar.

Hier erstmal die Logik hinter der Aufgabe:
Bild

Hier meine Lösung:

Code: Alles auswählen

verse = input ("enter a saying or poem: ")
word_list=verse.split(" ")
#print (word_list)
x = len(word_list)
new_words= []
#print (x)
range(0,x)

for word in range(x):
  print (word_list[word])
  if len(word_list[word]) <= 5:
    word_list[word] = word_list[word].lower()
  elif word >=7: 
    word_list[word] = word_list[word].upper()   

def word_mixer(word_list,new_words):
  word_list.sort()
  while x >= 5:
    new_words.append(word_list.pop(-4))
    new_words.append(word_list.pop(0))
    new_words.append(word_list.pop())
  else:
    new_words= word_list.sort()
    return 
word_mixer(word_list,new_words)
print (new_words)
Irgendwas haut wieder bei meiner Funktion nicht hin -_-.
Hier meine Fehlermeldung:
Traceback (most recent call last):
File "python", line 25, in <module>
File "python", line 21, in word_mixer
IndexError: pop from empty list

Warum ist meine list empty? In meiner Welt stehen da Wörter drinne :/ nur nicht in dieser...
new_words.append(word_list.pop(-4) geht bei kurzen Strings auch nicht... is mir schon klar...aber steht nicht in der Logik das ich genau das "prüfen" soll?

Für jede Hilfe bin ich Dankbar. Wenn ich mal soweit bin werde ich mich revanchieren...

Gruß Odox
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Odox: `x` bekommt vor der Schleife mal einen Wert. Und der ändert sich nicht auf magische Weise, also hast Du mit der ``while x > 5:``-Schleife wenn `x` grösser 5 ist, eine Endlosschleife. Da aber die `word_list` bei jedem Schleifendurchlauf drei Elemente kürzer wird, kracht es natürlich irgendwann.

Ein ``else``-Zweig bei Schleifen macht übrigens nur Sinn wenn im Schleifenkörper ein ``break`` vorkommt *und* potentiell die Möglichkeit besteht das die Schleife durch das ``break`` oder das normale Schleifenende verlassen wird.

Eine Schleife über `range(len(word_list))` ist übrigens „unpythonisch“. Da würde man in Python eine neue Liste mit den veränderten Werten erstellen. Den Index solltest Du auf jeden Fall nicht `word` nennen, denn es ist kein Wort sondern eine Zahl, genauer ein Index der an diesen Namen gebunden wird. Das ist total verwirrend das `word` zu nennen.

Die Signatur von `word_mixer()` stimmt nicht mit der Aufgabe überein. Und es macht auch keinen Sinn die noch leere Ergebnisliste als Argument zu übergeben. Man würde auch von der übergebenen Liste eine Kopie machen, weil die von der Funktion ja ”zerstört” wird, was für den Aufrufer sehr überraschend sein dürfte. Der möchte damit vielleicht noch etwas anderes machen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Odox
User
Beiträge: 9
Registriert: Montag 25. Juni 2018, 19:10

Erstmal Danke für deine Rückmeldung.
Vieles davon hab ich verstanden und auch schon umgesetzt.
@Odox: `x` bekommt vor der Schleife mal einen Wert. Und der ändert sich nicht auf magische Weise, also hast Du mit der ``while x > 5:``-Schleife wenn `x` grösser 5 ist, eine Endlosschleife. Da aber die `word_list` bei jedem Schleifendurchlauf drei Elemente kürzer wird, kracht es natürlich irgendwann.
Müsste behoben sein.
Ein ``else``-Zweig bei Schleifen macht übrigens nur Sinn wenn im Schleifenkörper ein ``break`` vorkommt *und* potentiell die Möglichkeit besteht das die Schleife durch das ``break`` oder das normale Schleifenende verlassen wird.
Auch gelöst. Siehe Code.
Eine Schleife über `range(len(word_list))` ist übrigens „unpythonisch“.
Welche stelle meintest du? Verstehe leider nicht was du meinst.
Da würde man in Python eine neue Liste mit den veränderten Werten erstellen.
Ist so eine Kopie nicht die Word_list? Ich mein das "Original" ist doch der String = verse?
Den Index solltest Du auf jeden Fall nicht `word` nennen, denn es ist kein Wort sondern eine Zahl, genauer ein Index der an diesen Namen gebunden wird. Das ist total verwirrend das `word` zu nennen.
Ja das verwirrt, hab ich geändert.

Die Signatur von `word_mixer()` stimmt nicht mit der Aufgabe überein. Und es macht auch keinen Sinn die noch leere Ergebnisliste als Argument zu übergeben. Man würde auch von der übergebenen Liste eine Kopie machen, weil die von der Funktion ja ”zerstört” wird, was für den Aufrufer sehr überraschend sein dürfte. Der möchte damit vielleicht noch etwas anderes machen.[/quote] Den Teil hab ich immer noch nicht richtig verstanden :/ ich hab irgendwo einen Denkfehler und versteh nicht warum er mir new_words nicht anzeigen will...

Hier erstmal mein "verbesserter Code".

Code: Alles auswählen

verse = input ("enter a saying or poem: ")
word_list=verse.split(" ")
#print (word_list)
x = len(word_list)
#print (x)
range(0,x)

for index in range(x):
  print (word_list[index])
  if len(word_list[index]) <= 5:
    word_list[index] = word_list[index].lower()
  elif len (word_list[index]) >=7: 
    word_list[index] = word_list[index].upper()   
print (word_list)

def word_mixer(word_list):
  
  while len(word_list) >= 5:
    new_words=word_list
    new_words.append(word_list.pop(-4))
    new_words.append(word_list.pop(0))
    new_words.append(word_list.pop())
  
  new_words=word_list.sort()
  return (new_words)

word_mixer(word_list)
print (word_list)
print (new_words)
Nochmals Danke für die Hinweise!

Gruß Odox
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Das Logik-Diagramm ist etwas verwirrend, weil hier von Index die Rede ist, obwohl man in Python gar keinen Index braucht. Es gibt Entscheidungsrauten, die aber gar keine Verzweigung haben, statt dessen aber etwas ausführen. `word_list` ist ein schlechter Variablenname, weil Typen nicht im Namen vorkommen sollten. `words` wäre deutlich besser.

Bei der Funktion word_mixer ist von einer Liste new_words die Rede, die bei Dir aber identisch ist zu word_list. So ist das aber nicht gemeint. new_words ist eine neue leere Liste. Laut Diagramm soll am Anfang sortiert werden, nicht zum Schluß, denn sonst ist die ganze Mixerei ja umsonst.

Zum Code: man sollte nicht ausführbaren Code und Funktionsdefinitionen durcheinander schreiben. Generell sollte auf oberster Ebene gar kein ausführbarer Code stehen, sondern nur Importe, Definitionen und Konstanten. Eingerückt wird mit 4 Leerzeichen pro Ebene, nicht zwei. Zwischen Funktionsname und öffnender Klammer kommt kein Leerzeichen, die Klammern bei `return` sind überflüssig.
Der `range`-Aufruf in Zeile 6 ist sinnfrei. `sort` sortiert die Liste inplace und liefert Nichts zurück.

Ohne etwas zu korrigieren, hier mal Dein Code an die Konventionen angepasst:

Code: Alles auswählen

def word_mixer(word_list):
    while len(word_list) >= 5:
        new_words = word_list
        new_words.append(word_list.pop(-4))
        new_words.append(word_list.pop(0))
        new_words.append(word_list.pop())
  
    new_words = word_list.sort()
    return new_words

def main():
    verse = input("enter a saying or poem: ")
    word_list = verse.split()

    word_list = [
        word.lower() if len(word) <= 5
        else word.upper() if len(word) >= 7
        else word
        for word in word_list
    ]
    print(word_list)

    new_words = word_mixer(word_list)
    print(word_list)
    print(new_words)
    
if __name__ == '__main__':
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Eine Komplettlösung die die Spezifikation allerdings nicht wörtlich umsetzt, aber äquivalente Ergebnisse liefern sollte:

Code: Alles auswählen

def change_case(word):
    """Change case to lower if it is a short word (≤5) or upper if it
    is a long word (≥7).  Otherwise return word unchanged.

    >>> change_case('SPAM')
    'spam'
    >>> change_case('Mississippi')
    'MISSISSIPPI'
    >>> 'Python'
    'Python'
    """
    if len(word) <= 5:
        word = word.lower()
    elif len(word) >= 7:
        word = word.upper()
    return word


def mix_words(words):
    """Return the words in the given iterable shuffled in a
    deterministically way.
    
    >>> words = ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff']
    >>> mix_words(words)
    ['bbb', 'aaa', 'fff']

    In contrast to the specification the given words can be any iterable
    and if it is a sequence it is not changed by this implementation.
    
    >>> words  # Not changed!
    ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff']

    .. warning::
        
        The algorithm from the specification drops up to five words
        from the input.  Especially when there are less than six words,
        all the input is dropped.  That is a bug in the specification,
        not in the implementation!

        Technically there is even one word too many dropped if the goal
        was to avoid an :exc:`IndexError` in the shuffle algorithm.
        Also per specification.
    
    >>> [(i, mix_words(words[:i])) for i in range(1, len(words) + 1)]
    [(1, []), (2, []), (3, []), (4, []), (5, []), (6, ['bbb', 'aaa', 'fff'])]
    
    The order of the given words doesn't matter at all.
    
    >>> import random
    >>> random.shuffle(words)
    >>> mix_words(words)
    ['bbb', 'aaa', 'fff']
    
    .. todo::
    
        An improvement would be to extend the result by the remaining,
        currently dropped words.
    """
    words = sorted(words)
    indices = [-5, 0, -1]
    # 
    # Determine minimum length of `words` so that indexing is still
    # guaranteed to work.
    # 
    min_length = max((-index if index < 0 else index + 1) for index in indices)

    result = list()
    # 
    # Could be ``>=`` to drop less words but specification says otherwise.
    # 
    while len(words) > min_length:  
        result.extend(words.pop(index) for index in indices)
    return result


def main():
    words = map(change_case, input('Enter a saying or poem: ').split())
    print(' '.join(mix_words(words)))


if __name__ == '__main__':
    main()
Boah, dieser doofe ständig falsch ratende Syntaxhighlighter nervt…
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Odox
User
Beiträge: 9
Registriert: Montag 25. Juni 2018, 19:10

Das Logik-Diagramm ist etwas verwirrend, weil hier von Index die Rede ist, obwohl man in Python gar keinen Index braucht. Es gibt Entscheidungsrauten, die aber gar keine Verzweigung haben, statt dessen aber etwas ausführen. `word_list` ist ein schlechter Variablenname, weil Typen nicht im Namen vorkommen sollten. `words` wäre deutlich besser.
Den variable Namen hab ich einfach aus dem Flussidgramm genommen. Verstehe aber was du meinst....
Bei der Funktion word_mixer ist von einer Liste new_words die Rede, die bei Dir aber identisch ist zu word_list. So ist das aber nicht gemeint. new_words ist eine neue leere Liste. Laut Diagramm soll am Anfang sortiert werden, nicht zum Schluß, denn sonst ist die ganze Mixerei ja umsonst.
Verständlich.
Zum Code: man sollte nicht ausführbaren Code und Funktionsdefinitionen durcheinander schreiben. Generell sollte auf oberster Ebene gar kein ausführbarer Code stehen, sondern nur Importe, Definitionen und Konstanten. Eingerückt wird mit 4 Leerzeichen pro Ebene, nicht zwei. Zwischen Funktionsname und öffnender Klammer kommt kein Leerzeichen, die Klammern bei `return` sind überflüssig.
Der `range`-Aufruf in Zeile 6 ist sinnfrei. `sort` sortiert die Liste inplace und liefert Nichts zurück.
Danke für den Hinweis mit den Konventionen, habe davon noch nicht wirklich in meinem Kurs gehört.
Ich muss erstmal alles verdauen, meld mich heute Abend nochmal ...
Odox
User
Beiträge: 9
Registriert: Montag 25. Juni 2018, 19:10

Hier die Lösung:

Code: Alles auswählen

def word_mixer(word_list):
  word_list.sort()
  new_words=[]
  while len(word_list) > 5:         
        new_words.append(word_list.pop(-5))             
        new_words.append(word_list.pop(0))             
        new_words.append(word_list.pop())             
  return new_words 

def main():
    verse = input("enter a saying or poem: ")
    word_list = verse.split()

    word_list = [
        word.lower() if len(word) <= 5
        else word.upper() if len(word) >= 7
        else word
        for word in word_list
    ]
    #print(word_list)
    ergebnis=word_mixer(word_list)
    #print(word_list)
    print(ergebnis)
    
if __name__ == '__main__':
    main()
Nochmals Danke an alle die mich unterstützt haben! Die Community ist echt super, hoffe das ich mich bald mal revanchieren kann!
Hehe am moisten hätte mir geholfen wenn ihr mir gesagt hättet: "Junge, ruf doch mal den word_mixer auf, wenn du ihn benutzen willst ;) *g*

Gruß Odox
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Dass eine Funktion die Liste, die man ihr übergibt, zerstört, ist sehr überraschend. Programmierer mögen keine Überraschungen, das sollte zumindest sehr deutlich dokumentiert werden. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 2 und mal 6.
Antworten