Seite 1 von 1

Oh Tannenbaum, oh Tannenbaum...

Verfasst: Mittwoch 21. Dezember 2011, 21:38
von Hyperion
Hallo zusammen,

inspiriert durch diesen Artikel habe ich mir zwei Möglichkeiten erarbeitet, wie man so einen Baum in Python erstellen kann. Ich beziehe mich auf die dritte Variante.

Ich will eine Funktion `xmastree` haben, der man einen beliebigen Text übergeben kann, und dieser dann in folgender Form ausgegeben wird:

Code: Alles auswählen

....|....
...t|t...
..st|ts..
.est|tse.
test|tset
....|....
Die erste und die letzte Zeile sind bei mir der Einfachheit halber identisch. Es wird also in jeder Zeile ein Teil des Textes ausgegeben, links und rechts beginnend mit dem letzten Zeichen. In jeder Zeile kommt ein Buchstabe mehr vom Text dazu, bis das Text in der vorletzten Zeile komplett vorhanden ist. Der Stamm wird durch das Zeichen "|" symbolisiert. Die Funktion soll einen zusätzlichen Parameter bekommen, der den Füll-Character¹ enthält.

Hier mal meine erste Variante mit Python Standardfunktionen:

Code: Alles auswählen

def itree_traditional(text, fill):
    space = fill * len(text)
    first = lambda : u"{}|{}".format(space, space)
    yield first()
    for index, _ in enumerate(text, 1):
        line = []
        for count, char in enumerate(text):
            if count < len(text)-index:
                line.append(fill)
            else:
                line.append(char)
        yield u"{}|{}".format("".join(line), "".join(reversed(line)))
    yield first()

def xmastree(text, fill="."):
    print u"\n".join(itree_traditional(text, fill))
Dann hab ich mal in den `itertools` gewühlt und bin auf folgendes gekommen:

Code: Alles auswählen

from itertools import islice, chain

def itree_islice(text, fill):
    space = fill * len(text)
    first = lambda : u"{}|{}".format(space, space)
    yield first()
    for index, _ in enumerate(text, 1):
        offset = len(text) - index
        left = "".join(chain(islice(space, offset), 
                             islice(text, offset, len(text))))
        yield "{}|{}".format(left, "".join(reversed(left)))
    yield first()

def xmastree(text, fill="."):
    print u"\n".join(itree_islice(text, fill))
Beide Funktionen ergeben folgendes Ergebnis:

Code: Alles auswählen

In [220]: xmastree("HappyChristmas", ".")
..............|..............
.............s|s.............
............as|sa............
...........mas|sam...........
..........tmas|samt..........
.........stmas|samts.........
........istmas|samtsi........
.......ristmas|samtsir.......
......hristmas|samtsirh......
.....Christmas|samtsirhC.....
....yChristmas|samtsirhCy....
...pyChristmas|samtsirhCyp...
..ppyChristmas|samtsirhCypp..
.appyChristmas|samtsirhCyppa.
HappyChristmas|samtsirhCyppaH
..............|..............
Wer hat noch etwas zu bieten? Egal ob pythonisch(er), kompakter oder spaßig? Oder evtl. in einer anderen Sprache?

Bin gespannt auf andere Lösungen :-)

¹ Wieso kann man in Code-Tags keine führenden Leerzeichen angeben? Diese werden in einigen Zeilen ignoriert :-(

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Mittwoch 21. Dezember 2011, 22:46
von 0x1cedd1ce

Code: Alles auswählen

def itree(text, fill, reverse=True):
    length = len(text)
    line = fill*length + '|' + fill*length
    yield line
    for i in range(length):
        if reverse:
            line = line[:length-i-1] + text[i] + line[length-i:length+i+1] + text[i] + line[length+i+1:2*length]
        else:
            line = line[:length-i-1] + text[-i-1] + line[length-i:length+i+1] + text[-i-1] + line[length+i+1:2*length]
        yield line
    yield fill*length + '|' + fill*length

def xmastree(text, fill='.', reverse=True):
    print('\n'.join(itree(text,fill,reverse)))
Man kann den Baum auch rückwärts ausgeben, dann steht die Spiegelschrift links und nicht rechts. Find ich schöner.

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Mittwoch 21. Dezember 2011, 23:22
von DasIch

Code: Alles auswählen

def xmastree(string, fill='.'):
    def make_reversed_left_side(string, fill):
        empty = fill * len(string)
        yield empty
        for i in xrange(len(string)):
            yield fill * i + string[i:]
        yield empty
    left_side = list(reversed(list(make_reversed_left_side(string, fill))))
    right_side = map(lambda x: u''.join(reversed(x)), left_side)
    print u'\n'.join(map('{0}|{1}'.format, left_side, right_side))

if __name__ == '__main__':
    xmastree('HappyChristmas')
Das geht jetzt sicherlich noch wesentlich eleganter aber dafür bin ich zu faul.

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 17:10
von nomnom

Code: Alles auswählen

def christmas_tree(string, fill="."):
    format = "{:%s^%d}" % (fill, len(string) * 2 + 1)
    return "\n".join(format.format(string[len(string)-i:]+'|'+"".join(reversed(string[len(string)-i:]))) for i in range(len(string)+1))
Die Zeile wird leider etwas lang und unübersichtlich, allerdings wollte ich es mit "".join() und einer List-Comprehension machen.

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 19:00
von snafu
Hab mal was zum Golfen geschrieben:

Code: Alles auswählen

for i in range(len(s),-1,-1):print s[i:].rjust(len(s),'.')+'|'+s[i:][::-1].ljust(len(s),'.')
Dummerweise fehlt die letzte Zeile. :lol:

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 19:07
von nezzcarth
Mit Spitze. ;)

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

def xmas_tree(message, fill='.'):
	def tree(message, padding):
		if message:
			tree(message[1:], padding)
			print('{0}|{1}'.format(message, message[::-1]).center(padding, fill))
		else:
			print('\\ /'.center(padding, fill))
			print('--O--'.center(padding, fill))
			print('/ \\'.center(padding, fill))
			print('|'.center(padding, fill))
	tree(message, len(message)*3)
	print('|||'.center(len(message)*3, fill))
	print('/|\\'.center(len(message)*3, fill))

def main():
	xmas_tree("Weihnachten")

if __name__ == '__main__':
	main()

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 19:13
von snafu
So, jetzt ist auch die letzte Zeile drin... :) (wie konnt ich meinen Freund Modulo nur übesehen ^^)

Code: Alles auswählen

for i in range(len(s),-2,-1):print s[i%(len(s)+1):].rjust(len(s),'.')+'|'+s[i%(len(s)+1):][::-1].ljust(len(s),'.')

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 19:46
von snafu
Ich unterbiete nochmal ein bißchen meine letzte Version:

Code: Alles auswählen

for i in range(len(s),-2,-1):print'{:.^{}}'.format(s[i%(len(s)+1):]+'|'+s[i%(len(s)+1):][::-1],len(s)*2+1)
(ab Python 2.7)

Und dann noch was mit GC und Semikolon:

Code: Alles auswählen

l=len(s);print'\n'.join('{:.^{}}'.format(s[i%(l+1):]+'|'+s[i%(l+1):][::-1],l*2+1)for i in range(l,-2,-1))

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 20:21
von webspider
Glaube wir haben schonmal einen vorläufigen Gewinner :wink:

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 20:26
von Hyperion
webspider hat geschrieben:Glaube wir haben schonmal einen vorläufigen Gewinner :wink:
Zumindest fürs Golfen ;-)

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 21:05
von 0x1cedd1ce

Code: Alles auswählen

for i in list(range(len(s)+1))+[0]:print('.'*(len(s)-i)+s[:i][i::-1]+'|'+s[:i]+'.'*(len(s)-i))
oder wenn die liste andersherum läuft

Code: Alles auswählen

for i in list(range(len(s),-1,-1))+[len(s)]:print('.'*i+s[i:][::-1]+'|'+s[i:]+'.'*i)
Edit: Leerzeichen und überflüssige Klammern entfernt

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 21:21
von snafu
Aufbauend auf der letzten Lösung:

Code: Alles auswählen

for i in range(len(s),-1,-1)+[len(s)]:print'.'*i+s[i:]+'|'+s[i:][::-1]+'.'*i

Re: Oh Tannenbaum, oh Tannenbaum...

Verfasst: Donnerstag 22. Dezember 2011, 21:25
von 0x1cedd1ce
Der Baum in einer Liste

Code: Alles auswählen

['{0}{1}|{2}{0}'.format('.'*i,s[::-1],s) for i,s in [(i,s[i:]) for i in range(len(s),-1,-1)]+[(len(s),'')]]
Version 2 noch schöner

Code: Alles auswählen

['{0:.>{2}}|{1:.<{2}}'.format(p[::-1],p,len(s)) for p in [s[i:] for i in range(len(s),-1,-1)]+['']]