joker_list enthält nicht die letter_lists

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo!
Vom folgenden Code erwarte ich, dass die Liste joker_lists um die ABC-Buchstaben angewachsen ist. Was mit print(letter_list) ausgegeben wird, ist korrekt. Dies hänge ich an die Liste joker_lists an. Sie enthält diese Elemente am Ende aber nicht, warum?

Code: Alles auswählen

# -*- coding: utf-8 -*-
"""
Created on Wed Jul 14 09:21:25 2021

@author: User
"""

letters = 'öl  tze'
alphabet = 'abcdefghijklmnopqrstuvwxyzäöü'
letter_list = []

for single_letter in letters:
    letter_list.append(single_letter)

joker_list = []
if "  " in letters:
    for i, alphabet_letter in enumerate(alphabet):
        letter_list.append(alphabet_letter)
        for j, alphabet_letter in enumerate(alphabet):
            letter_list.append(alphabet_letter)
            print(letter_list)      
            joker_list.append(letter_list)
            letter_list.pop()
        letter_list.pop()
        
for item in joker_list:
    print(item)
print(len(joker_list))

Grüße, Strawk
Ich programmiere erfolglos, also bin ich nicht.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Denk mal hier drueber nach:

Code: Alles auswählen

liste = []
mehr_liste = [liste, liste, liste]
print(mehr_liste)
liste.append("ich soll keine Referenzen auf Datenstrukuren behandeln, als ob sie Kopien waeren")
print(mehr_liste)
liste.clear()
print(mehr_liste)
Sowas ist der Grund, warum man Datenstrukturen nicht irgendwie mit append/pop/clear & co massiert, sondern stattdessen neu aufbaut, und dann im Zweifel an den alten Namen bindet. Weil das voellig unuebersichtlich wird.

Edit: ad hominems rausgenommen, tut mir leid.
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hab drüber nachgedacht. Finde dennoch keine Lösung.
Ich programmiere erfolglos, also bin ich nicht.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wirklich? So duenn? Keine Fragen zum Beispiel? Keinerlei Erkenntnis, was da passiert?
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo!
Das deutsche Alphabet hat mit Umlauten 29 Buchstaben. 29 x 29 ist 841. Ich möchte eine Liste von Listen wie diese:
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ö', 'ä']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ö', 'ö']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ö', 'ü']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'a']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'b']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'c']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'd']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'e']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'f']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'g']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'h']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'i']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'j']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'k']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'l']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'm']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'n']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'o']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'p']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'q']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'r']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 's']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 't']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'u']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'v']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'w']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'x']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'y']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'z']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'ä']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'ö']
['ö', 'l', ' ', ' ', 't', 'z', 'e', 'ü', 'ü']
841 insgesamt. (Hintergrund: 2 Joker im Spiel Scrabble) Und worüber ich mir heute seit 8 Uhr den Kopf zerbreche: Wenn doch print(letter_list) das Korrekte ausgibt und ich doch gleich im Anschluss dieses Korrekte an joker_list anhänge, wieso in aller Welt enthält dann joker_ist nicht diese Listen-Liste. Ich komm nicht drauf, kann machen, was ich will.
Grüße!
Ich programmiere erfolglos, also bin ich nicht.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Jedes letter_list append hat ein pop. letter_list ist also am Ende deiner Schleife wieder unveraendert. Und in joker_list hast du halt nur eine Referenz auf letter_list, keine der temporaeren Aenderungen wirkt sich aus. Wenn du die *Elemente* der letter_list in joker_list haben willt, dann brauchst du extend statt append. Ob das richtig ist? KA. Ich begreife nicht, was das alles soll.
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

1. Wir kommen der Sache näher mit dem, was du sagst. Zunächst zu extend statt append: Das ist es nicht, denn so würde die Liste 7569 lang. Aber mich interessiert, was du bzgl. Referenz und "keine Änderung wirkt sich nicht aus" gesagt hast. Wie muss das Programm denn aussehen, damit joker_list die 841 'Listchen' enthält?
2. Es gibt eine 223-zeilige voll lauffähige Version des Programmes. Ziel heute war, das darin verletzte DRY-Prinzip in der Funktion get_hints() zu bessern. Soll ich dieses ganze Programm mal posten?
Grüße
Ich programmiere erfolglos, also bin ich nicht.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Der Fehler ist, dass Du nicht 841 Listen hast, sondern nur EINE. Und diese EINE ist 841mal in der jocker_list-Liste.
Damit solche Fehler nicht auftreten, ist die einfache Regel, niemals Listen zu verändern, sondern immer neue Listen zu erzeugen.

Code: Alles auswählen

letters = 'öl  tze'
alphabet = 'abcdefghijklmnopqrstuvwxyzäöü'
letter_list = list(letters)

joker_list = []
if "  " in letters:
    for alphabet_letter1 in alphabet:
        for alphabet_letter2 in alphabet:
            joker_list.append(letter_list + [alphabet_letter1, alphabet_letter2])
        
for item in joker_list:
    print(item)
print(len(joker_list))
Mit itertools geht das ganze noch viel eleganter:

Code: Alles auswählen

from itertools import combinations_with_replacement

letters = 'öl  tze'
alphabet = 'abcdefghijklmnopqrstuvwxyzäöü'

joker_list = [
    letters + ''.join(alphabet_letters)
    for alphabet_letters in combinations_with_replacement(alphabet, 2)
]
Wenn ich Dich richtig verstanden habe, suchst Du aber eher soetwas:

Code: Alles auswählen

from itertools import combinations_with_replacement

letters = 'öl  tze'
alphabet = 'abcdefghijklmnopqrstuvwxyzäöü'

joker_list = []
for alphabet_letters in combinations_with_replacement(alphabet, letters.count(' ')):
    word = letters
    for letter in alphabet_letters:
        word = word.replace(' ', letter, 1)
    jocker_list.append(word)
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo!
Verstehe ich das richtig? In dem Moment, wo der alphabet_letter mit letter_list.pop() wieder aus der Liste letter_list weggenommen wird, wird er auch aus der joker_list weggenommen? Gibt es denn keinen Operator, der die Liste autonom macht?
Grüße, Strawk
Ich programmiere erfolglos, also bin ich nicht.
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

joker_list.append(letter_list.copy())
Ich programmiere erfolglos, also bin ich nicht.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Ich kann dir da mal dieses Video empfehlen:
Ned Batchelder - Facts and Myths about Python names and values - PyCon 2015
https://www.youtube.com/watch?v=_AEJHKGk9ns

Mich würde nur mal interessieren, wie lange du schon mit Python arbeitest ohne dieses Wissen?
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie schon geschrieben ändert man keine Liste, und macht dann auch keine Kopie, sondern erzeugt einfach jeweils neue Listen.
Benutzeravatar
Strawk
User
Beiträge: 227
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo!
Ich habe seit 1994 eine Stoffwechselstörung im Gehirn; das Lernen fällt mir extrem schwer. Mit Python arbeite ich seit 2017/2018. Das habe ich in den letzten Wochen gemacht:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Name:        scrabble.py
# Purpose:     create german words with given letters
#              optional: get words that fit at position(s) with certain letters(s)
#              optional: consider if there's a joker or two
#
# Author:      ---
#
# Created:     07/13/2021
# License:     n/a
#-------------------------------------------------------------------------------
"""
    create german words with given letters
    and write them into a file
    for use in the board game "Scrabble"
    
    1 main class that, beside constructor, contains 3 private functions
    and 1 public function:
    
        constructor (__init__):
            creates a set with all german words
            (over 2 million) by reading file
        
        3 private functions:
            
            _calc_permutations:
                creates a list of all possible permutations (combinations) of
                given letter-record
                In: letters
                Out: all_permutations
                
            _create_results:
                creates the result-lists
                depending of filter instructions are given,
                calls _filter_on_position
                In: all_permutations, all_words
                Out: total_result
                
            _filter_on_position:
                filters existing words for desired single letters and
                their desired position
                In: results, filter_dict
                Out: results (filtered)
        
        1 public function:
            
            get_hints:
                calculate the joker-options by calling the functions
                _calc_permutations and _create_results the necessary times
                and thus get word-hints for the player
                In: filter_dict, letters
"""
import os
from itertools import chain, permutations
import time
# main class
class Letter_record():
    def __init__(self, filename):
        """
        creates a set with all german words (over 2 million)
        by reading file
        
        In:
        filename
        
        Out:
        all_words
        """
        all_words = set()
        dic = open(filename, 'r')
        for line in dic:
            all_words.add(line.strip())

        self.all_words = all_words        

    # private functions:
    def _calc_permutations(self):
        """
        creates a list of all possible permutations (combinations) of
        given letter-record
        
        In:
        letters
        
        Out:
        all_permutations
        """
        chars = []
        for i in self.letters:
            if i == ' ':
                self.letters.remove(i)
        for c in self.letters:
            chars.append(c)
        all_permutations = list(
            chain.from_iterable(
                permutations(chars, length)
                for length in range(1, len(chars) + 1)
            )
        )
        self.all_permutations = all_permutations
    
    def _create_results(self):
        """
        creates the result-lists
        depending on filter instructions are given, calls _filter_on_position
        
        In:
        all_permutations, all_words
        
        Out:
        total_result
        """
        results = []
        for item in self.all_permutations:
            word = "".join(item)
            for possible_word in [word, word.capitalize()]:
                if possible_word in self.all_words:
                    if possible_word not in results and possible_word not in self.total_result:
                        results.append(possible_word)
        self.results = results
        if len(self.filter_dict) != 0:
            self._filter_on_position()
        self.total_result.extend(self.results)
    
    def _filter_on_position(self):
        """
        filters existing words for desired single letters and
        their desired position
        
        In:
        results, filter_dict
        
        Out:
        results (filtered)
        """
        filtered_words = []
        for word in self.results:
            # ensure all filter conditions take effect, no matter how many
            all_filter_conditions = 0
            for position, letter in self.filter_dict.items():
                try:
                    if word[position] == letter or word[position] == letter.capitalize():
                        all_filter_conditions += 1
                except:
                    continue
            if all_filter_conditions == len(self.filter_dict):
                filtered_words.append(word)
        self.results = filtered_words

    #public function
    def get_hints(self, letters='öl  tze', filter_dict={0 : 'ö', 1 : 'l', 2 : 'g', 3 : 'ö', 4 : 't', 5 : 'z'}):
        """
        calculate the joker-options by calling the functions
        _calc_permutations and _create_results the necessary times
        and thus get word-hints for the player
        
        In:
        filter_dict, letters
        """
        self.filter_dict = filter_dict
        self.letters = letters
        self.total_result = []
        alphabet = 'abcdefghijklmnopqrstuvwxyzäöü'
        # turn string into list
        letter_list = []
        for single_letter in self.letters:
            letter_list.append(single_letter)
        
        # important here: 2 space-characters
        if "  " in letters:
            for i, alphabet_letter in enumerate(alphabet):
                letter_list.append(alphabet_letter)
                
                for j, alphabet_letter in enumerate(alphabet):
                    letter_list.append(alphabet_letter)
                    self.letters = letter_list
                    self._calc_permutations()
                    self._create_results()
                    # prevent letter-list from increasing inner loop
                    letter_list.pop()
                # prevent letter-list from increasing outer loop
                letter_list.pop()
        
        elif " " in letters:
            for i, alphabet_letter in enumerate(alphabet):
                letter_list.append(alphabet_letter)
                self.letters = letter_list
                self._calc_permutations()
                self._create_results()
                # prevent letter-list from increasing
                letter_list.pop()
        
        elif " " not in letters:
            self._calc_permutations()
            self._create_results()
        
def main():
    def write_to_file(total_result):
        try:
            os.mkdir('results')
        except:
            pass
        resultfile = open('results/results.txt','w+')
        for result_counter, word in enumerate(total_result):
            # suppress line feed at EOF
            if result_counter + 1 == len(total_result):
                resultfile.write("%d: %s" % (result_counter + 1, word))
            else:
                resultfile.write("%d: %s\n" % (result_counter + 1 , word))
        resultfile.close()
    
    set_a = Letter_record('wordbooks/german.dic')
    set_a.get_hints()
    write_to_file(set_a.total_result)
    del set_a

if __name__ == "__main__":
    start = time.time()
    main()
    ende = time.time()
    print('program took {:5.3f} minutes'.format((ende-start)/60))
Grüße, Strawk
Ich programmiere erfolglos, also bin ich nicht.
Antworten