Kann man das auch noch besser schreiben?

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
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Ihr habt mir schon sehr geholfen bei zwei Funktionen. Aber die letzte namens 'marked_notcommon_keylist' ist vielleicht noch nicht optimal.

Code: Alles auswählen

from collections import Counter

def marked_notcommon_keylist(iterable,most_common,keys):
    config=[]
    for item in iterable:

        key_dict = {}
        for index,element in enumerate(item):
            key_dict[keys[index]] = element
            
        config.append([item!=most_common,key_dict])

    return config

def most_in(sequence):
    most_common = None
    if sequence:
        most_common = Counter(sequence).most_common(1)[0][0]
    return most_common
        
def remove_trailing(sequence, value):
    while sequence and sequence[-1] == value:
        sequence.pop()

def main():
    my_list = [
        (15,0,0),
        (75,0,1),
        (75,0,1),
        (25,0,1),
        (75,0,1),
        (15,0,0),
        (0,0,0),
        (0,0,0),
        (0,0,0)]

    remove_trailing(my_list,(0,0,0))
    most_common = most_in(my_list)
    columnconfig = None
    if most_common:
        columnconfig = marked_notcommon_keylist(my_list,most_common,('minsize','pad','weight'))
    
    print(most_common,'\n',columnconfig)

 
if __name__ == '__main__':
    main()
Hier soll die Liste my_list in eine andere unter Verwendung von Keywörtern umgewandelt werden. Dabei soll außerdem markiert werden, ob es sich bei dem Eintrag von einem von most_common abweichenden handelt.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

config sollte keine Liste von Listen sondern eine von Tupeln sein. key_dict ist kein Wörterbuch von Schlüsseln, sondern da stehen konkrete Werte drin, der Name ist also falsch. Wenn die Einträge Namen haben, warum verwendest Du nicht von Anfang an Namedtuples?

Code: Alles auswählen

def marked_notcommon_keylist(iterable,most_common,keys):
    return [
        (item != most_common, dict(zip(keys, item))
        for item in iterable
    ]
Insgesamt stellt sich mir die Frage, was Du eigentlich machen willst. Woher kommen die Werte in my_list? Was soll mit diesen passieren?

In Deinem Hauptprogramm zeigt sich schon schön, warum es besser ist Exceptions zu benutzen. most_in liefert None, wenn die Liste leer ist, das Ergebnis prüfst Du dann wieder auf None, um weiter zu machen. So verursacht der Sonderfall leere Liste im weiteren Verlauf ständig Sonderfallprüfungen. Bei Exceptions bräuchtest Du das alles nicht.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:Insgesamt stellt sich mir die Frage, was Du eigentlich machen willst. Woher kommen die Werte in my_list?
siehe hier: viewtopic.php?f=1&t=40548&p=309674#p309674
Sirius3 hat geschrieben:Was soll mit diesen passieren?
Also die Werte in der Liste kommen aus rowconfigure und columnconfigure:

Code: Alles auswählen

import tkinter as tk
#import DynTkInter as tk # for GuiDesigner


# === general grid table definition =================
def grid_general_rows(container,rows,**kwargs):
    for row in range(rows):
        container.rowconfigure(row,**kwargs)
 
def grid_general_cols(container,columns,**kwargs):
    for column in range(columns):
        container.columnconfigure(column,**kwargs)

# Application definition ============================

class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # general grid definition ==============================
        grid_general_rows(self,4, minsize = 25, pad = 0, weight = 1)
        grid_general_cols(self,4, minsize = 75, pad = 0, weight = 1)
        # individual grid definition ===========================
        self.rowconfigure(0,pad=0, weight=1, minsize=16)
        self.columnconfigure(0,pad=0, weight=1, minsize=16)
        # widget definitions ===================================
        self.button = tk.Button(self,name='#0_button',text='button')
        self.button.grid(row=1, column=1)

#Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Application().mainloop()
Und diesen Code will ich wieder aus den erzeugten Widgets und den benutzten columnconfigure und rowconfigure nach etwaiger Veränderung im GuiDesigner generieren.

Das ist bereits generierter Code. Jetzt brauche ich noch die andere Richtung, nämlich ausgehend von so einem Script unter Benutzung dieser Listen wieder das Script generieren zu können.

Und dazu muss ich aus dieser Liste, die Liste mit der Markierung auf individuelle config und den key Worten gewinnen.

Und ein Tuple sollen die Einträge der Ergebnisliste nicht sein, denn im Grid Layout beim GuiDesigner, will man die Werte ändern.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: rowconfigure liefert doch schon Wörterbücher, warum die also in ein Tuple umwandeln? Die überflüssigen 0-en bekommst Du doch nur, wenn Du mehr Spalten abfrägst, wie configuriert sind. Lass das doch einfach sein, dann brauchst Du auch kein Strip. Und die general-grid-definition ist auch nur eine Erfindung (Funktion) von Dir. Im Normalfall dürfte es also keine zwei Spalten mit den selben Werten geben und wenn, dann würde man das direkt mit einer Schleife setzen, weil es kann ja gut sein, dass Spalten 0 bis 7 schmal und Spalten 8 bis 15 breit sind. Da ist also **ein** Defaultwert nur für die Hälfte gut.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: rowconfigure liefert doch schon Wörterbücher, warum die also in ein Tuple umwandeln?
Hatte nicht gedacht, dass das geht:

Code: Alles auswählen

a = { 'key1' : 1 , 'key2' : 2 }
b = { 'key1' : 1 , 'key2' : 2 }

print(a==b)
Bei Tupeln war ich mir sicher. Ginge damit auch das meist vorkommende Element?

Außerdem bringt es nicht so viel, da es sein kann, dass jemand nicht alle keywords angibt und dann geht der Vergleich nicht. Ich muß also sowieso nachbearbeiten.

Also es funktioniert nicht: TypeError: unhashable type
Zuletzt geändert von Alfons Mittelmeyer am Sonntag 21. Mai 2017, 14:16, insgesamt 6-mal geändert.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:Die überflüssigen 0-en bekommst Du doch nur, wenn Du mehr Spalten abfrägst, wie configuriert sind.
Die 0 llen bekommt man, wenn man ein Grid Layout für eine gewisse Anzahl von Spalten macht und sich dann entscheidet mit weniger Spalten auszukommen. Da kann man doch nur den nicht mehr gewollten Rest mittels row- oder columnconfigure wieder auf 0 stellen, oder?
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3: Danke, das wäre jetzt also super kurzer Code:

Code: Alles auswählen

from collections import Counter

def marked_notcommon_keylist(iterable,most_common,keys):
    return [
        [item != most_common, dict(zip(keys, item))]
        for item in iterable
    ]

def most_in(sequence):
    most_common = None
    if sequence:
        most_common = Counter(sequence).most_common(1)[0][0]
    return most_common
       
def remove_trailing(sequence, value):
    while sequence and sequence[-1] == value:
        sequence.pop()
 

def main():
    my_list = [
        (15,0,0),
        (75,0,1),
        (75,0,1),
        (25,0,1),
        (75,0,1),
        (15,0,0),
        (0,0,0),
        (0,0,0),
        (0,0,0)]

    remove_trailing(my_list,(0,0,0))
    most_common = most_in(my_list)
    columnconfig = marked_notcommon_keylist(my_list,most_common,('minsize','pad','weight'))

    print(most_common,'\n',columnconfig)
 
 
if __name__ == '__main__':
    main()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:Im Normalfall dürfte es also keine zwei Spalten mit den selben Werten geben
Das könnte man ja damit abfangen, dass man das generelle Gridlayout erst ab einer gewissen Anzahl gleicher Werte und erst ab einer gewissen Anzahl überhaupt im ganzen Programm umsetzt, die größer ist, als die Zeilen für die Definitionen der betreffenden Funktionen.
Sirius3 hat geschrieben:und wenn, dann würde man das direkt mit einer Schleife setzen, weil es kann ja gut sein, dass Spalten 0 bis 7 schmal und Spalten 8 bis 15 breit sind. Da ist also **ein** Defaultwert nur für die Hälfte gut.
Dann ist es doch nicht schlecht, wenn Spalten 0 bis 7 nur eine Code Zeile erfordern.
Schleifen für den Rest wären auch nicht schlecht, aber zuvor gilt es andere Grenzfälle zu behandeln oder es sein zu lassen.

Bild

Das ist etwa ein Gridlayout mit 4 Zeilen und 4 Spalten. Zeile 0 und Spalte 0 habe ich auf ein individuelles Layout gesetzt und als generelles Layout 0,0,0 gewählt. Und was kommt raus?

Trailing 0,0,0 am Ende wird abgeschnitten. Das heißt ein generelles Gridlayout mit nur einer Zeile und einer Spalte:

Bild

Aber was soll man da tun? Anders geht es wohl kaum, wenn man das Grid Layout nun ohne spezielle Funktion allein aus rowconfigure und columnconfigure gewinnt.

Naja, man kann es dann ja wieder manuell ändern.

Vielleicht sollte man trailing null nicht generell abschneiden, sondern nur da, wo es erforderlich ist, nämlich im Grid Layout des GuiDesigners? Also, wenn man die Anzahl von Zeilen und Spalten verringert. Und dann nur ab einer gewissen Position.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Also, Problem gelöst. Nicht generell Trailing 0 abschneiden, sondern nur nach Bedarf im Grid Layout. Und das passt dann:

Code: Alles auswählen

import tkinter as tk
#import DynTkInter as tk # for GuiDesigner

# for development ==================================
def show_grid_table(container,rows,columns):
    for row in range(rows):
        for column in range(columns):
            tk.Frame(container,relief= 'solid',bd =1,bg ='#b3d9d9').grid(row=row, column=column, sticky='news')

# === general grid table definition =================
def grid_general_rows(container,rows,**kwargs):
    for row in range(rows):
        container.rowconfigure(row,**kwargs)
 
def grid_general_cols(container,columns,**kwargs):
    for column in range(columns):
        container.columnconfigure(column,**kwargs)

# Application definition ============================

class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # general grid definition ==============================
        grid_general_rows(self,4, minsize = 0, pad = 0, weight = 0)
        grid_general_cols(self,4, minsize = 0, pad = 0, weight = 0)
        # individual grid definition ===========================
        self.rowconfigure(0,minsize=15, weight=1, pad=0)
        self.columnconfigure(0,minsize=15, weight=1, pad=0)
        # widget definitions ===================================
        self.button1 = tk.Button(self,name='#0_button1',text='button1')
        self.button1.grid(row=1, column=1)
        self.button2 = tk.Button(self,name='#1_button2',text='button2')
        self.button2.grid(row=2, column=2)
        self.button3 = tk.Button(self,name='#2_button3',text='button3')
        self.button3.grid(row=3, column=3)

#Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Application().mainloop()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer:Und die general-grid-definition ist auch nur eine Erfindung (Funktion) von Dir. Im Normalfall dürfte es also keine zwei Spalten mit den selben Werten geben und wenn, dann würde man das direkt mit einer Schleife setzen, weil es kann ja gut sein, dass Spalten 0 bis 7 schmal und Spalten 8 bis 15 breit sind. Da ist also **ein** Defaultwert nur für die Hälfte gut.
Das Problem hat sich erledigt, denn ich habe jetzt die passende Lösung gefunden.

- das Programm arbeitet bis auf eine Kleinigkeit wie bisher. Ist eine grid Layout Definition bereits da, interessiert diese Liste von Tupeln, aus der man sie auch noch gewinnen kann, nicht mehr.
- das heißt, was bei der Grid Layout Bearbeitung im GuiDesigner noch mit dieser Liste von Tupeln geschieht, ist ohne Belang
- das Abschneiden von Trailing (0,0,0) ist unnötig und wäre ein Fehler
- Grid Layout Definitiion entstand bisher beim Editieren des Grid Layouts im GuiDesigner und beim Laden von DynTkInter Gui Scripten
- nur falls noch keine Grid Layout Definition (aus anderen Quellen) da ist, wird gegebenenfalls eine durch rowconfigure oder columnconfigure definierte erzeugt

Den Algorithmus habe ich geändert. Es existiert nun neben dieser Liste von Tupeln noch ein Dictionary. Das Dictionary enthält auch Eintgräge, die aus rowconfigure und columnconfigure erzeugt wurden, Aber dabei handelt es sich nicht um den augenblicklichen Zustand, sondern um die Information für welche Spalten oder Zeilen entsprechende configures angewandt wurden, etwa:

{ (75,0,1) : { 1,2,3,4,5 } , ... }

Nur wenn man die gleiche Grid Layout Definition über alle Zeilen oder Spalten angewandt hat, unabhängig vom Endzustand, ist damit dann eine generelles Grid Layout definiert. Definiert ist ein solches immer, nur andernfalls ist es (0,0,0). Auch bei nur einer Zeile oder Spalte gilt als generelles Grid Layout (0,0,0)

Ein generelles Grid Layout von (0,0,0) braucht man nicht zu exportieren, denn (0,0,0) ist es von selber.
Auch braucht man dafür nichts zu implementieren, dass keine (0,0,0) configure Definitionen geschrieben werden, denn nur vom generellen Grid Layout abweichende Definitionen werden geschrieben. Eine Ausnahme dabei ist allerdings eine (0,0,0) Definition am Ende. Ist eine solche vorhanden, wird sie geschrieben. Schließlich definiert sie ja die Breite oder Länge des Grid Layouts. Für das Programm spielt es keine Rolle, aber wenn man im GuDesigner eine Grid Tabelle mit soundsoviel Zeilen oder Spalten definiert hat, soll man sie nachher beim Nacheditieren auch wieder so bekommen.

Meine Lösung sieht jetzt so aus:

Code: Alles auswählen

def get_grid_multilist(iterable,most_used,keys):
    return [ [item != most_used, dict(zip(keys, item))] for item in iterable ]

def most_of(how_many):
    count = 0
    element = None
    for key,value in how_many.items():
        if len(value) > count:
            count = len(value)
            element = key
    return element,count
        
def get_gridconfig(iterable,how_many):

    if not iterable:
        return None,[]

    if len(iterable) == 1:
        most_used = (0,0,0)
    else:
        most_used,count = most_of(how_many)
        if count < len(iterable):
            most_used = (0,0,0)

    config = get_grid_multilist(iterable,most_used,('minsize','pad','weight'))
    general = [len(iterable)]
    general.extend(most_used)
    return tuple(general),config
Und aus:

Code: Alles auswählen

        # general grid definition ==============================
        grid_general_rows(self,4, minsize = 0, pad = 0, weight = 0)
        grid_general_cols(self,4, minsize = 0, pad = 0, weight = 0)
        # individual grid definition ===========================
        self.rowconfigure(0,minsize=15, weight=1, pad=0)
        self.columnconfigure(0,minsize=15, weight=1, pad=0)
wird:

Code: Alles auswählen

        # individual grid definition ===========================
        self.rowconfigure(0,weight=1, minsize=15, pad=0)
        self.rowconfigure(3,weight=0, minsize=0, pad=0)
        self.columnconfigure(0,weight=1, minsize=15, pad=0)
        self.columnconfigure(3,weight=0, minsize=0, pad=0)
Gute Lösung?

PS: Im Normalfall dürfe es keine Zwei Spalten under Reihen mit denselben Werten geben? Doch das habe ich hier vor Kurzem in dieser Art gesehen:

Code: Alles auswählen

grid_general_rows(self,8, weight = 1)
Antworten