2010-07-01 3 views
9

In Lisp, können Sie so etwas wie diese:Iterate ein Format-String über eine Liste

(setf my-stuff '(1 2 "Foo" 34 42 "Ni" 12 14 "Blue")) 
(format t "~{~d ~r ~s~%~}" my-stuff) 

Was wäre der Pythonic Weg dieselbe Liste iterieren das? Die erste Sache, die in den Sinn kommt, ist:

mystuff = [1, 2, "Foo", 34, 42, "Ni", 12, 14, "Blue"] 
for x in xrange(0, len(mystuff)-1, 3): 
    print "%d %d %s" % tuple(mystuff[x:x+3]) 

Aber das fühlt sich nur peinlich für mich. Ich bin sicher, dass es einen besseren Weg gibt?


Nun, es sei denn, jemand später ein besseres Beispiel bietet, denke ich gnibbler Lösung der schönste ist \ am nächsten, obwohl es zunächst nicht ganz so offensichtlich sein kann, wie es das tut, was es tut:

mystuff = [1, 2, "Foo", 34, 42, "Ni", 12, 14, "Blue"] 
for x in zip(*[iter(mystuff)]*3): 
    print "{0} {1} {2}".format(*x) 
+1

Nebenbei, ist nicht so umständlich so ein wunderbares Wort? Es sieht nur * komisch aus! –

+2

Es sieht im Vergleich peinlich aus, aber es ist wirklich nicht so schlimm. – ChaosPandion

+2

+1, weil ich keine Ahnung habe, ob Sie sich auf meinen Kommentar oder den Code beziehen. * Bitte * nicht klarstellen, die Mehrdeutigkeit ist viel unterhaltsamer/interessanter! –

Antwort

11
mystuff = [1, 2, "Foo", 34, 42, "Ni", 12, 14, "Blue"] 
for x in zip(*[iter(mystuff)]*3): 
    print "%d %d %s"%x 

Oder mit .format

mystuff = [1, 2, "Foo", 34, 42, "Ni", 12, 14, "Blue"] 
for x in zip(*[iter(mystuff)]*3): 
    print "{0} {1} {2}".format(*x) 

Wenn der Formatstring nicht fest einprogrammiert ist, können Sie es analysieren, um herauszufinden, wie viele Begriffe pro Zeile

from string import Formatter 
num_terms = sum(1 for x in Formatter().parse("{0} {1} {2}")) 

Alles zusammen ergibt

mystuff = [1, 2, "Foo", 34, 42, "Ni", 12, 14, "Blue"] 
fmt = "{0} {1} {2}" 
num_terms = sum(1 for x in Formatter().parse(fmt)) 
for x in zip(*[iter(mystuff)]*num_terms): 
    print fmt.format(*x) 
+0

Ich mag diese Lösung wirklich, und ich war zuerst wirklich verwirrt, aber nachdem ich den Code, der wirklich elegant ist, gehackt habe. –

+0

@Wayne Werner, gut auf dich für die Ausarbeitung, warum es funktioniert –

3

Für den Anfang würde ich die neuere Zeichenfolge Formatierung Methoden in 2.6+

print "{0} {1} {2}".format(*mystuff[x:x+3]) 
+0

Ich hatte das vergessen. Reinigt es ein wenig ... –

4

verwenden ich denke join die ähnliche Funktion in Python ist:

(format t "~{~D, ~}" foo) 

print(foo.join(", ")) 

Es ist ein wenig schlechter, wenn Sie mehrere Elemente im Inneren haben, wie Sie sehen, aber wenn Sie eine group-by Funktion haben (die ohnehin wirklich nützlich ist!), Ich denke, man kann es ohne zu viel Mühe arbeiten. Etwas wie:

mystuff = [1, 2, "Foo", 34, 42, "Ni", 12, 14, "Blue"] 
print(["%d %d %s" % x for x in group(mystuff, 3)].join("\n")) 
+0

Ja, mit der Zugabe einer speziellen Generatorfunktion könnte man es wirklich schön aussehen lassen. –

+0

Ja, ich schätze, es hängt davon ab, wie viel du betrügen willst. Sie könnten 'FORMAT' nach Python portieren und' FORMAT (True, ~ {~ d ~ r ~ s ~% ~} ", my_stuff) sagen, wenn Sie sich an einem Wochenende wirklich gelangweilt haben. :-) – Ken

+0

Ich bin versucht worden! Natürlich wünsche ich mir auch, dass die '~r' auch Teil von Python-Bibliotheken sind ... Es gibt bereits ein Modul auf Sourceforge: http: // sourceforge.net/projects/pynum2word/ –

2

ich am meisten Pythonic würde sagen, wäre die Liste tiefer zu machen:

mystuff = [(1, 2, "Foo"), (34, 42, "Ni"), (12, 14, "Blue")] 
for triplet in mystuff: 
    print "%d %d %s" % triplet 
+0

das ist im Grunde, was gnibblers Lösung schafft: '[x für x in zip (* [iter (mystuff)] * 3)]' = '[(1, 2, 'foo'), (34, 42, 'ni'), (12, 14, 'blau')] 'Ziemlich glatt, neh? –

+0

Ich weiß das, aber ich denke, es ist mehr Pythonic, nur um die Liste in dieser Form zu haben. Das war die ursprüngliche Frage, oder? –

+0

Nun, ich war etwas mehrdeutig, also habe ich den Wortlaut korrigiert. Ich war wirklich mehr am Iterieren/Formatieren interessiert, indem ich eine bestimmte Anzahl von Listenwerten pro Iteration verbrauchte. Aber in Bezug auf das gesamte "Programm" wäre Ihre Lösung eher pythisch –

0

Ein zwei Liner basierend auf Wright:

mystuff = [1, 2, "Foo", 34, 42, "Ni", 12, 14, "Blue"] 
print '\n'.join("{0},{1},{2}".format(*mystuff[x:x+3]) for x in xrange(0, len(mystuff)-1, 3)) 
1
stuff = [1, 2, "Foo", 34, 42, "Ni", 12, 14, "Blue"] 

it = iter(stuff) 
itn = it.next 

print '\n'.join("%d %d %s" % (el,itn(),itn()) 
       for el in it) 

Sehr verständlich, ich denke