kleine hilfe für ASCII darstelungen

Code-Stücke können hier veröffentlicht werden.
Antworten
Costi
User
Beiträge: 545
Registriert: Donnerstag 17. August 2006, 14:21

dieser kliener script kann für die erweiterte darstelung von text behilflich sein:
feedback würde mich freuen




Code: Alles auswählen


class field:
	def __init__(self, x, y):
		self.x = x
		self.y = y
		self.spielfeld = eval(('[' + x * ('[' + (y-1) * ('" ",') + '" "' + ']' ) + ']').replace("][", "],["))#geht egentlich auch einfacher...

	def set(self, x, y, char):
		self.spielfeld[-1*y][x-1] = char
		
	
	def show(self):
		print (self.x + 2) * "#"
		st = ""
		for balken in self.spielfeld:
			kastens = ""
			for kasten in balken:
				kastens += kasten
			st += "#" + kastens + "#\n"
			kasten = ""
		st += (self.x + 2) * "#" 
		print st

	
	def get(self, x, y):
		return self.spielfeld[-1*y][x-1]

		
if __name__ == "__main__":
	def g(x): return x*3 + 4#mueste euch bekannt sein.....
	f = field(50,50)
	for i in range(1,50):
		if g(i) >= 50: break
		f.set(i, g(i),"W")
	f.show()

	
	
cp != mv
Python 47
User
Beiträge: 574
Registriert: Samstag 17. September 2005, 21:04

Hallo Costi,

1.Bitte, bitte kein eval
2.Zeile 7 ist zu lang
3.Klassennamen groß schreiben
4.#!/usr/bin/env python
# -*- coding: iso-8859-1 -*- würde ich generell an den Anfang setzen.
mfg

Thomas :-)
BlackJack

Und hier würde es sich anbieten, das `Field` so zu implementieren, das setzen und auslesen mit der Syntax zum Elementzugriff funktioniert. Ausserdem ist `show` die klassische Umsetzung einer `__str__()`-Methode:

Code: Alles auswählen

from itertools import count, takewhile


class Field(object):
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.data = [[' '] * width for dummy in xrange(height)]
    
    def __getitem__(self, (x, y)):
        return self.data[-y][x - 1]
    
    def __setitem__(self, (x, y), value):
        self.data[-y][x - 1] = value
    
    def __str__(self):
        vertical_border = '#' * (self.width + 2)
        result = [vertical_border]
        for row in self.data:
            result.append('#' + ''.join(row) + '#')
        result.append(vertical_border)
        return '\n'.join(result)


def main():
    field = Field(50, 50)
    for coordinates in takewhile(lambda (dummy, y): y < 50,
                                 ((i, i * 3 + 4) for i in count(1))):
        field[coordinates] = 'W'
    print field
(Man möge mir die Verwendung von `takewhile()` verzeihen. :-))
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Das ist aber eine unschöne Methode.

Code: Alles auswählen

from itertools import takewhile, count

for coordinates in takewhile(lambda (dummy, y): y < 50,
                                 ((i, i * 3 + 4) for i in count(1))):
    print coordinates,

Code: Alles auswählen

(1, 7) (2, 10) (3, 13) (4, 16) (5, 19) (6, 22) (7, 25) (8, 28) (9, 31) (10, 34) (11, 37) (12, 40) (13, 43) (14, 46) (15, 49)


Der endlose iterator 'count()' ist mMn überflüssig. Dafür gibts 'range()' oder 'xrange()'. Aber im großen und ganzen ist das Konstrukt Käse.

Code: Alles auswählen

print 
for coordinates in takewhile(lambda (dummy, y): y < 50,
                                 ((i, i * 3 + 4) for i in xrange(1, 50))):
    print coordinates,

Code: Alles auswählen

(1, 7) (2, 10) (3, 13) (4, 16) (5, 19) (6, 22) (7, 25) (8, 28) (9, 31) (10, 34) (11, 37) (12, 40) (13, 43) (14, 46) (15, 49)
So gehts auch und kommt das gleiche raus.

Code: Alles auswählen

print
for coordinates in zip(xrange(1,50), xrange(7, 50, 3)):
    print coordinates,

Code: Alles auswählen

(1, 7) (2, 10) (3, 13) (4, 16) (5, 19) (6, 22) (7, 25) (8, 28) (9, 31) (10, 34) (11, 37) (12, 40) (13, 43) (14, 46) (15, 49)

Wenn die Aufgabenstellung nicht wäre das ab 1 inkrementiert wird, dann würde es sogar so gehen:

Code: Alles auswählen

print
for coordinates in enumerate(xrange(7, 50, 3)):
    print coordinates,

Code: Alles auswählen

(0, 7) (1, 10) (2, 13) (3, 16) (4, 19) (5, 22) (6, 25) (7, 28) (8, 31) (9, 34) (10, 37) (11, 40) (12, 43) (13, 46) (14, 49)
lg
BlackJack

XtraNine hat geschrieben:Das ist aber eine unschöne Methode.

Code: Alles auswählen

from itertools import takewhile, count

for coordinates in takewhile(lambda (dummy, y): y < 50,
                                 ((i, i * 3 + 4) for i in count(1))):
    print coordinates,
[...]

Der endlose iterator 'count()' ist mMn überflüssig. Dafür gibts 'range()' oder 'xrange()'.
Da müsste man dann aber sicherstellen, dass die Obergrenze des `xrange()` ausreicht. Und wenn man die 50 ändert, dann darf man nicht vergessen auch das `xrange()` anzupassen. Der endlose Iterator "kostet" nicht mehr als `xrange()` und man kann ihn unverändert lassen, egal wo man die Abbruchbedingung ansetzt.
So gehts auch und kommt das gleiche raus.

Code: Alles auswählen

print
for coordinates in zip(xrange(1,50), xrange(7, 50, 3)):
    print coordinates,
Da würde ich das erste `xrange()` aus den oben genannten Gründen durch ``count(1)`` ersetzen. Und `zip()` durch `izip()`. :-)
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Erstmal vorweg. Natürlich 'izip()' und nicht 'zip()'. Da hast recht :)

Naja, den Iterator anzupassen ist wohl eher nicht das Problem. Ich gehe davon aus das solch ein Teil für gewöhnlich in einer Funktion gekapselt ist, die dann halt einen Parameter hat.

Code: Alles auswählen

from itertools import izip
def foo(counts):
    for coordinates in izip(xrange(1,counts), xrange(7,counts, 3)):
        print coordinates,
Was mich aber generell immer noch stört sind halt die 2 'xrange()'
BlackJack hat geschrieben:Da müsste man dann aber sicherstellen, dass die Obergrenze des `xrange()` ausreicht.
Naja die Begründung ist nicht wirklich eine gütige. Natürlich sind 'xrange()' und 'range()' in ihrer möglichen Anzahl iterationen begrenzt. Das ist überall wo man beide genanten einsetzt. Trotzdem fängt man jetzt nicht an und benutzt jetzt über all stat...

Code: Alles auswählen

for i in xrange(50):
    print i,
...ein...

Code: Alles auswählen

from itertools import takewhile, count
for i in takewhile(lambda y: y < 50, ( i-1 for i in count(1)) ):
    print i,
... ;) Zugegeben, die 'takewhile()' Variante ist in grunde nicht "endlich" (wenn man es genau nimmt ist sie auch nicht unendlich bzw. was ist die obergrenze für eine Zahl in Python) und dadurch flexibler, dennoch fangen wir bestimmt nicht jetzt alle an und ersetzen unsere 'range()' durch diese Variante un shcon gar nicht wenn es um 50 Iterationen geht.

Und wie in diesen Fall, geht man auch in 90% alle anderen möglichen Anwendungen, nicht von einer hohen hohen iteration überhalb von 'short' und 'long' aus. Falls ja kann man immer noch Dookies 'longxrange()' nutzen (Warum hat das noch keiner der Python Entwickler ins Python 2.5 hinzugefügt? :?) oder aus deiner Version das Äquivalent basteln, das sogar kürzer als Dookies Version wäre.

Aber mal zu zu Thema zurück:
Was hällst du von dieser Variante Jack?:

Code: Alles auswählen

def f2():
    field = Field(50,50)
    
    cntr = 0
    for i in xrange(7, 50, 3):
        cntr += 1
        field[(cntr, i)] = 'W'
Macht das gleiche wie deine Version mit dem Vorteil, das nicht erstmal mit 'for' über 'count()' itereiert und dessen mit 'takewhile()' darüber iteriert und dann mit 'for' über 'takewhile()' iteriert werden muss. :)

lg
BlackJack

XtraNine hat geschrieben:
BlackJack hat geschrieben:Da müsste man dann aber sicherstellen, dass die Obergrenze des `xrange()` ausreicht.
Naja die Begründung ist nicht wirklich eine gütige. Natürlich sind 'xrange()' und 'range()' in ihrer möglichen Anzahl iterationen begrenzt. Das ist überall wo man beide genanten einsetzt. Trotzdem fängt man jetzt nicht an und benutzt jetzt über all stat...

Code: Alles auswählen

for i in xrange(50):
    print i,
...ein...

Code: Alles auswählen

from itertools import takewhile, count
for i in takewhile(lambda y: y < 50, ( i-1 for i in count(1)) ):
    print i,
Irgendwie glaube ich Du hast mein Argument nicht verstanden. Es geht nicht darum das `xrange()` nicht über `sys.maxint` hinauskommt, sondern das man immer beide Obergrenzen anpassen muss. Und rein aus "Selbstdokumentation" ist ein ``count(1)`` besser als ein ``xrange(1,count)`` wie in Deinem Beispiel, weil man sich dann vielleicht fragt, ob das einen Grund hat das dort bei `count` die Grenze gezogen wird und nicht bei ``count/2`` oder noch niedriger. Bei einem ``count(1)`` ist auf den ersten Blick klar das die Grenze nur vom zweiten Argument zur `izip()`-Funktion abhängt.
Aber mal zu zu Thema zurück:
Was hällst du von dieser Variante Jack?:

Code: Alles auswählen

def f2():
    field = Field(50,50)
    
    cntr = 0
    for i in xrange(7, 50, 3):
        cntr += 1
        field[(cntr, i)] = 'W'
Macht das gleiche wie deine Version mit dem Vorteil, das nicht erstmal mit 'for' über 'count()' itereiert und dessen mit 'takewhile()' darüber iteriert und dann mit 'for' über 'takewhile()' iteriert werden muss. :)
Ist natürlich nicht so aufwändig wie die `takewhile()`-Variante aber nicht so schön wie:

Code: Alles auswählen

for coordinates in izip(count(1), xrange(7, 50, 3)):
    field[coordinates] = 'W'
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

BlackJack hat geschrieben:[...]

Code: Alles auswählen

for coordinates in izip(count(1), xrange(7, 50, 3)):
    field[coordinates] = 'W'
Dann sind wir letztendlich doch dort hingekommen wo wir hin wollten -> Reduzierung (wie in mit meiner FL aus dem Thread HL vs. FL) ;) Zugegeben diese Möglichkeiten sieht auch am besten aus.

Du schriebst ja auch in deinen vorigen poste das du das erste 'xrange()' durch einen 'count()' ersetzte und das ganze durch 'izip()' jagen würdest. Hab mich aber bewusst für die Inkrement-Variante mit 'cntr += 1' entschieden *g -> Und zwar wie sieht es nun mit den calls/performance aus? Das würde mich interessieren.

'izip()' liefert ja einen Generator zurück und iteriert gleichzeitig über 'count()' und 'xrange()', die auch jeweils nen Generator zurückliefern bzw. das 'next()' für beide ausgeführt wird von 'izip()'. Nun iteriert aber 'for' auch über 'izip()'. Das macht für mich 4 Objekte die iteriert werden müssen :? Sehe ich das richtig? Oder muss ich mir das mit dem 'yield' doch anders vorstellen?

Naja meine Inkrement variante iteriert insgesamt nur über xrange(). Also nur über ein einziges Objekt. Das restliche wird mit 'cntr+1' gemacht was ja keine Iteration ist.

Natürlich ist der call/performance in so eine Fall unerheblich (weil im nicht spürbaren bereich), aber denoch würde mich generell interessieren wie das ist. (Halt damit ichs richtig verstehe)

BTW: Magst du mit deinem 'takewhile()' Beispiel eine 'longxrange()' schreiben und das in Dookies Thread posten? Oder soll/darf ich das machen? *gg

lg
BlackJack

Da sind 3 Iteratoren. `count()` liefert einen, `xrange()` ist "iterable", liefert also indirekt auch einen und dann `izip()`. Der von `izip()` wird von der Schleife benutzt.

Das mit der Geschwindigkeit muss man nachmessen. Wahrscheinlich ist die prozedurale Lösung in diesem Beispiel schneller als die Funktionale. Daraus sollte man aber keine generellen Schlüsse ziehen, sondern immer den konkreten Fall nachmessen. Dazu muss man beide Lösungen implementieren. Das lohnt sich also erst wenn man genau weiss, dass die schon vorhandene Lösung ein Flaschenhals im Programm darstellt.
Antworten