ListComprehension - MagicSquare

Code-Stücke können hier veröffentlicht werden.
Antworten
zottelkopf
User
Beiträge: 4
Registriert: Mittwoch 11. Oktober 2017, 20:03

Hallo,
ich bin neu in Python, habe aber in anderen Sprachen sehr gute Kenntnisse. Seit ein paar Wochen interessiere ich mich sehr für Python. Vieles ist neu... :-(
Ich hab jetzt mal so als Erstes ne Klasse geschrieben, die ein 'magisches Quadrat' erstellt. Zur Erläuterung: ein magisches Quadrat mit Seitenlänge n enthält alle Zahlen von 1 bis n² wobei die Zahlen in dem Quadrat so angeornet sind, dass die Summe aller Zeilen, Spalten und der beiden Diagonalen stets gleich sind. Für Quadrate mit ungerader Seitenlänge gibt es eine Vorschrift, die ich jetzt aber nicht näher erläutern möchte.
Ich bin sehr faszinier von der 'ListComprehension'. Ich kann das Quadrat momentan nur mit Hilfe von einer Schleife befüllen (siehe Quelltext).
Kann mir einer von Euch (bzw. geht es überhaupt) diese Vorschrift als ListComprehension anbieten?

Liebe Grüße und das ist mein erster Beitrag (Jungfernfahrt... ich hoffe ich mach mich nicht zum Deppen :? )

Alex

class magic(object):
'''
magic(size) constructs a 2-dimensional matrix[0..size-1][0..size-1]
in which all numbers from 1 to size**2 contains, so that
the sum of the numbers in each row, column
and both diagonales are equal.
magic() does the same with a default value: size = 5.

get() returns the matrix as a list.
set(size) changes the size of the matrix and recalculate the matrix.
size() returns the amount of rows / columns of the matrix.
sum() returns the sum of each row, column and diagonale.
print() prints out the square
'''
def __init__(self, size = 5):
self.__size = size

if self.__size <= 0:
raise ValueError

if not self.__size % 2:
raise ValueError

self.__matrix = [[None for x in range(self.__size)] for y in range(self.__size)]

for x1 in range(self.__size):
x2 = (self.__size // 2 + x1) % self.__size
y2 = (x2 + 1) % self.__size
for y1 in range(self.__size):
self.__matrix[x2][y2] = x1 * self.__size + y1 + 1
x2 = (x2 - 1) % self.__size
y2 = (y2 + 1) % self.__size

def get(self):
return self.__matrix

def set(self, size):
self.__init__(size)

def size(self):
return self.__size

def sum(self):
return (self.__size ** 3 + self.__size) // 2

def print(self):
d = str(len(str(self.__size ** 2))+1)
format_string = '%' + d + 'd'
for row in range(self.__size):
for col in range(self.__size):
print(format_string % self.__matrix[row][col], end = '')
print()
zottelkopf
User
Beiträge: 4
Registriert: Mittwoch 11. Oktober 2017, 20:03

Sorry Leute, ich hab noch nicht geblickt, wie ich den Quelltext mitsamt den Einrückungen etc. darstellen kann... - SORRY... Aber ich weiß, Ihr könnt das lesen!

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

@zottelkopf: bei Python ist die Einrückung essentiell. Daher gibt es hier im Forum Code-Tags, die man über das Dropdown »Code auswählen« einfügen kann.

Zum Code: Python hat ein paar Konventionen. Variablennamen werden klein_mit_unterstrich geschrieben, Klassen CamelCase. »magic« sollte also »MagicSquare« heißen. Um das "=" bei Keyword-Argumenten werden keine Leerzeichen gesetzt. Die Doppelten Unterstriche bei Deinen Instanzattributen sind falsch, da gehört maximal einer hin. Beim werfen von Exceptions sollte ein Exemplar der Ausnahme generiert werden, am besten mit einem hilfreichen Fehlertext: »raise ValueError("size must be larger than 0")«. Getter und Setter sind in Python unerwünscht, dafür gibt es Properties. Besser sind aber unveränderliche Klassen, es gibt eigentlich keinen Grund, »size« nachträglich ändern zu wollen, man kann ja einfach ein neues Exemplar erzeugen. »__init__« sollte (außer bei Vererbung) nie direkt aufgerufen werden. Bei »print«: Formatierungsstrings kenne '*'. Über Listen werden direkt iteriert und nicht indirekt über einen Index.

Code: Alles auswählen

class MagicSquare(object):
    '''
        MagicSquare(size) constructs a 2-dimensional matrix[0..size-1][0..size-1]
                    in which all numbers from 1 to size**2 contains, so that
                    the sum of the numbers in each row, column
                    and both diagonales are equal.

        size      the amount of rows / columns of the matrix.
        sum      the sum of each row, column and diagonale.
        print()     prints out the square
    '''
    def __init__(self, size=5):
        if size <= 0:
            raise ValueError("size must be larger than 0")

        if size % 2 == 0:
            raise ValueError("size must be odd")

        self.matrix = [[None] * size for _ in range(size)]
        for x1 in range(size):
            x2 = (size // 2 + x1) % size
            y2 = (x2 + 1) % size
            for y1 in range(size):
                self.matrix[x2][y2] = x1 * size + y1 + 1
                x2 = (x2 - 1) % size
                y2 = (y2 + 1) % size

    @property:
    def size(self):
        return len(self.matrix)

    @property:
    def sum(self):
        return (self.size ** 3 + self.size) // 2

    def print(self):
        size = len(str(self.size ** 2)) + 1
        for row in self.matrix:
            for cell in row:
                print('%*d' % (size, cell), end='')
            print()
Du hast einen Algorithmus, der die Matrix nicht in einer Reihenfolge füllt, daher kann man hier keine Listcomprehension benutzen.
zottelkopf
User
Beiträge: 4
Registriert: Mittwoch 11. Oktober 2017, 20:03

Vielen Dank,

du hast mir bei den Konventionen sehr weiter geholfen. Wie gesagt... ich bin neu - daher bin ich um Beiträge, wie Du ihn gemacht hast - sehr dankbar. Ich komm da schon rein.
Ja, das geht 'kreuz und quer' ... ich hab mir schon gedacht, dass ListComprehension da nicht geht... - aber danke für Deine Info.
Bis bald,

Alex
zottelkopf
User
Beiträge: 4
Registriert: Mittwoch 11. Oktober 2017, 20:03

@Sirius3

Danke nochmal... Nachdem ich Deinen überarbeiteten Quelltext nochmal angesehen habe, sind mir so einige Sachen klar geworden, die ich aus anderen Sprachen so nicht kenne.

Dank Dir bin ich mir jetzt sicher, dass ich in diesem Forum auf kompetente Beiträge hoffen kann.

Liebe Grüße,
Alex
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Geht natürlich, wenn auch nicht wirklich schön:

Code: Alles auswählen

def val(a, b, size):
    c = (b - a - 1) // 2 + (1 - b % 2) * (1 + size // 2)
    d = a + c - size // 2
    return (d  % size) * size + c % size + 1
matrix = [[val(a,b,size) for b in range(size)] for a in range(size)]
Antworten