Umsortieren von Listen

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
crabnebul
User
Beiträge: 2
Registriert: Freitag 4. August 2017, 17:50

Hey guys,
ich habe eine lange Liste von Wörtern in einer text file. Wenn ich die Liste direkt drucken würde, bekäme ich unmengen von Seiten. Um dies zu umgehen, würde ich gerne auf eine Seite n (~3) Spalten packen um möglichst viel Platz auszunutzen. Um das zu bewerkstelligen würde ich gerne Python benutzen. (wenn es einfacher geht ist auch gut). Der Einfachheit halber würde ich es gerne an einem kleinen Beispiel entwickeln. Angenommen ich möchte am Ende so eine Darstellung haben:
1 3 5
2 4 6
7 9 11
8 10 12
und zu begin sind meine Daten in einem array:

Code: Alles auswählen

data=range(1,13)
Wie kann ich die Datenliste so manipulieren, damit ich sie wie angegeben in eine file schreiben kann? Danke für jede Hilfe.
cs Tom
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

Da du range schon kennst gehe ich davon aus du kannst die Basics?

Du solltest deine Aufgabe mit for-Range und open() erledigen können.

https://docs.python.org/3/tutorial/cont ... statements

https://docs.python.org/3/tutorial/inpu ... ting-files
nezzcarth
User
Beiträge: 1634
Registriert: Samstag 16. April 2011, 12:47

Wenn du dir es einfach machen möchtest, öffne die Textdatei doch einfach mit LibreOffice Writer (oder Word) und stell bei den Seiteneinstellungen die Anzahl der Spalten auf einen entsprechend hohen Wert.

Eine andere Variante unter Linux wäre, 'column' (aus util-linux) zu nehmen.


Wenn es Python sein soll, geht es zum Beispiel in einer simplen Variante ohne Importe so:

Code: Alles auswählen

In [1]: def columnize(iterable, n=3, filler=' '):
   ...:     cache = []
   ...:     for i, item in enumerate(iterable, 1):
   ...:         cache.append(item)
   ...:         if not i % n:
   ...:             print(filler.join(cache))
   ...:             cache = []
   ...:     if cache:
   ...:         print(filler.join(cache))
   ...:         

In [2]: with open('/usr/share/dict/ngerman') as f:
   ...:     lines = [line.strip() for line in f]

Etwas kürzer geht es z.B. mit itertools.takewhile.
BlackJack

@nezzcarth: Schau Dir noch mal das gewünschte Muster an, so einfach ist das nicht.
crabnebul
User
Beiträge: 2
Registriert: Freitag 4. August 2017, 17:50

Danke für deine Hilfe. Ich hab mir das Leben etwas leider gemacht und schreib jetzt einfach alles Zeile per Zeile. Mit Excel hat es auch easy geklappt wenn auch nicht sehr elegant.

Code: Alles auswählen

fo=open("final.txt","w")
#/usr/share/dict/american-english
with open('/usr/share/dict/american-english') as f:
	lines = [line.strip() for line in f]

columns=9
count =1
for item in lines:
	if (count%columns)==0:
		fo.write("\n")
		count+=1
	else:
		line = item.replace("\n"," ")
		fo.write(line+",")
		count+=1
fo.close()
Zuletzt geändert von Anonymous am Freitag 4. August 2017, 22:31, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@crabnebul: Die Ausgabedatei wird zu früh geöffnet. Die Reihenfolge ist ja a) Eingabedatei einlesen, b) Ausgabedatei schreiben. Also braucht man die Ausgabedatei auch nicht vor dem Lesen der Eingabedatei öffnen. Zumindest nicht wenn man die Daten vorher komplett in den Speicher liest.

Auch für die Ausgabedatei sollte man ``with`` verwenden.

`f` und `fo` sind keine guten Namen.

Die Klammern um die Modulo-Operation sind überflüssig.

Da sowohl im ``if``- als auch im ``else``-Zweig am Ende `count` hochgezählt wird, sollte das nur *einmal* hinter diesem Konstrukt stehen.

Der `replace()`-Aufruf ist sinnlos weil `item` kein '\n' mehr enthalten kann, die wurden beim Einlesen ja schon mit `strip()` entfernt.

Zwischenstand:

Code: Alles auswählen

    with open('/usr/share/dict/american-english') as in_file:
        lines = [line.strip() for line in in_file]

    with open('test.txt', 'w') as out_file:
        columns = 9
        count = 1
        for line in lines:
            if count % columns == 0:
                out_file.write('\n')
            else:
                out_file.write(line + ',')
            count += 1
Das manuelle hochzählen von `count` kann man mit `enumerate()` loswerden. Und man muss bei diesem Vorgehen gar nicht alle Zeilen in den Speicher laden (ungetestet):

Code: Alles auswählen

    with open('/usr/share/dict/american-english') as lines:
        with open('test.txt', 'w') as out_file:
            columns = 9
            for count, line in enumerate(lines, 1):
                if count % columns == 0:
                    out_file.write('\n')
                else:
                    out_file.write(line.strip() + ',')
Wenn man allerdings alles in den Speicher lädt, dann wäre eine ``for``-Schleife und „slicing“ wahrscheinlich meine Wahl (ungetestet):

Code: Alles auswählen

    with open('/usr/share/dict/american-english') as in_file:
        lines = [line.strip() for line in in_file]

    with open('test.txt', 'w') as out_file:
        columns = 9
        for i in range(0, len(lines), columns):
            out_file.write('{},\n'.format(','.join(lines[i:i + columns])))
nezzcarth
User
Beiträge: 1634
Registriert: Samstag 16. April 2011, 12:47

@BlackJack: Ich bin davon ausgegangen, dass die eigentliche Aufgabe ist, eine zeilenbasierte Datei möglichst platzsparend umzuformatieren, damit man sie gut ausdrucken kann. Da ist das konkrete Muster m.M.n. egal, solange eine eindeutige, konsistente Leserichtung erkennbar ist.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Vielleicht möchte man die Spaltenanfänge hübsch untereinander haben, denn bei der simplen Herangehensweise sind sie ja versetzt sobald Wörter mit unterschiedlicher Länge vorkommen. Dazu ist ein wenig mehr Aufwand nötig:

Code: Alles auswählen

from __future__ import print_function

def get_line_template(widths, sep='  '):
    if len(widths) == 0:
        return ''
    specs = ['{{:{0}.{0}}}'.format(width) for width in widths[:-1]]
    specs.append('{{:.{0}}}'.format(widths[-1]))
    return sep.join(specs)

def format_lines(lines, widths, sep='  '):
    template = get_line_template(widths, sep)
    for line_items in lines:
        try:
            yield template.format(*line_items)
        except IndexError:
            new_widths = widths[:len(line_items)]
            new_template = get_line_template(new_widths, sep)
            yield new_template.format(*line_items)

def columnize(items, num_columns, sep='  ', outfile=None):
    widths = [
        max(map(len, items[i::num_columns]))
        for i in range(num_columns)
    ]
    lines = (
        items[i : i + num_columns]
        for i in range(0, len(items), num_columns)
    )
    for line in format_lines(lines, widths, sep):
        print(line, file=outfile)

def simple_test():
    items = ['Monty', 'Python', 'Spam', 'Ham', 'Eggs', 'Parrot']
    for i in range(1, len(items)):
        columnize(items, i)
        print()

if __name__ == '__main__':
    simple_test()
BlackJack

Falls nezzcarth's Vermutung zutrifft würde sich vielleicht auch das `textwrap`-Modul aus der Standardbibliothek anbieten:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8
from __future__ import absolute_import, division, print_function
from textwrap import wrap


def main():

    with open('/usr/share/dict/american-english') as in_file:
        content = in_file.read()

    lines = wrap(content.replace('\n', ', '), width=80, break_on_hyphens=False)

    with open('test.txt', 'w') as out_file:
        out_file.writelines(line + '\n' for line in lines)


if __name__ == '__main__':
    main()
Ergebnis:
[codebox=text file=Unbenannt.txt]A, A's, AA's, AB's, ABM's, AC's, ACTH's, AI's, AIDS's, AM's, AOL, AOL's,
ASCII's, ASL's, ATM's, ATP's, AWOL's, AZ's, AZT's, Aachen, Aaliyah, Aaliyah's,
Aaron, Abbas, Abbasid, Abbott, Abbott's, Abby, Abby's, Abdul, Abdul's, Abe,
Abe's, Abel, Abel's, Abelard, Abelson, Abelson's, Aberdeen, Aberdeen's,
Abernathy, Abernathy's, Abidjan, Abidjan's, Abigail, Abilene, Abner, Abner's,
Abraham, Abraham's, Abram, Abram's, Abrams, Absalom, Abuja, Abyssinia,
Abyssinia's, Abyssinian, Abyssinian's, Ac, Ac's, Acadia, Acadia's, Acapulco,

zit's, zither, zither's, zithers, zits, zodiac, zodiac's, zodiacal, zodiacs,
zombi, zombi's, zombie, zombie's, zombies, zombis, zonal, zone, zone's, zoned,
zones, zoning, zonked, zoo, zoo's, zoological, zoologist, zoologist's,
zoologists, zoology, zoology's, zoom, zoom's, zoomed, zooming, zooms, zoos,
zucchini, zucchini's, zucchinis, zwieback, zwieback's, zygote, zygote's,
zygotes, Ångström, éclair, éclair's, éclairs, éclat, éclat's, élan,
élan's, émigré, émigré's, émigrés, épée, épée's, épées, étude,
étude's, études,[/code]
Antworten