CSV zeilenweise trennung und in mehre Dateien splitten

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.
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Eine andere Variante mit ``groupby()``:

Code: Alles auswählen

In [1]: import string; from operator import itemgetter; from itertools import groupby

In [2]: chars = ((i // 3, ch) for i, ch in enumerate(string.ascii_lowercase))

In [3]: for index, group in groupby(chars, key=itemgetter(0)):
   ...:     values = map(itemgetter(1), group)
   ...:     print(index, list(values))
   ...:
0 ['a', 'b', 'c']
1 ['d', 'e', 'f']
2 ['g', 'h', 'i']
3 ['j', 'k', 'l']
4 ['m', 'n', 'o']
5 ['p', 'q', 'r']
6 ['s', 't', 'u']
7 ['v', 'w', 'x']
8 ['y', 'z']
Sie ist einerseits etwas "gesprächiger", aber andererseits IMHO auch etwas verständlicher.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Sirius3: Ich hatte natürlich auch an ``groupby`` gedacht - aber für den OP ist das wohl etwas überfordernd. Als Anti-Pattern empfinde ich hier das ``len`` im ``range`` nicht - es geht im Zugriff ja schließlich um den Index und *nicht* (wie beim echten Anti Pattern) um den Zugriff auf *ein* Objekt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hyperion hat geschrieben:Als Anti-Pattern empfinde ich hier das ``len`` im ``range`` nicht - es geht im Zugriff ja schließlich um den Index und *nicht* (wie beim echten Anti Pattern) um den Zugriff auf *ein* Objekt.
Auch ich sehe das in diesem Zusammenhang nicht als Anti-Pattern. Man hat einen direkten Zugriff ohne Umwege. In der Regel sind Slices für diverse Objekttypen auch performanter implementiert als die Variante über das Iterator-Protokoll.

Andererseits kann der direkte Indexzugriff bzw Slicing hier bloß als Grundlagenwissen dienen. Einen ``csv.reader`` kann man nämlich nicht mit Indexzugriffen abfragen. Und an der Stelle ist die ``groupby``-Variante IMHO gar keine so schlechte Wahl. Auch wenn das kein wirklich eleganter Weg ist. Aber das sind die Alternativen ja auch nicht.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi,
Hyperion hat geschrieben: aber für den OP ist das wohl etwas überfordernd.
ganz recht. ;)
Ich gebs auf.

VG und trotzdem Danke für die Hinweise und Erklärungen
kid
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Warum das? Du musst es doch nicht alles in wenige Zeilen pressen. Teile dir die Aufgabe doch in verschiedene Funktion auf. Einlesen der CSV-Datei, Zerteilen der Daten, Schreiben einer neuen CSV-Datei und dann fügst du das ganze noch zusammen. Du musst das nur Stück für Stück lösen, dann wird es auch ganz einfach.
Das Leben ist wie ein Tennisball.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Es scheitert an den Grundlagen. Ich bekomme die Daten nicht mal eingelesen.
So hatte ichs versucht:

Code: Alles auswählen

# -*- coding: utf-8 -*-
import csv, os, sys

datei = 'C:/Skripttesten/scripttest/test/test.csv' # relevanter Pfad mit Dateien
AnzahlZeilen =180
liste = []
y = 3*i
x = x-3
with open(datei, 'rb') as f:
   reader = csv.reader(f)

   for nr, row in enumerate(reader):
      liste.append(row)

   #einzeldatei = open('C:/Skripttesten/scripttest/test/Test2/Teil.csv', 'wb')  #öffne die gesamte Datei
   #writer = csv.writer(einzeldatei)
   #writer.writerows(liste)
Dann hört es aber auf und es macht alles nicht wirklich sind.
Es ist auch gar nicht mehr wichtig, das Skript für mich. Es hätte es nur gern geschafft. So ein Skript könnte man ja immer mal gebrauchen, aber wie gesagt es wäre jetzt erstmal nur noch zum Spaß.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hmmm,

jetzt bin ich doch ein Stück weiter:

Code: Alles auswählen

# -*- coding: utf-8 -*-
import csv, os, sys

datei = 'C:/Skripttesten/scripttest/test/test.csv' # relevanter Pfad mit Dateien
AnzahlZeilen =180
liste = []
block_size = 3
with open(datei, 'rb') as f:
   reader = csv.reader(f)

   for row in reader:
      liste.append(row)

   for start in range(0, len(liste), block_size):
       print(liste[start:start+block_size])   

   #einzeldatei = open('C:/Skripttesten/scripttest/test/Test2/Teil.csv', 'wb')  #öffne die gesamte Datei
   #writer = csv.writer(einzeldatei)
   #writer.writerows(liste)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Na jetzt hast du es doch fast. Nun musst du das Schreiben der Dateien nur noch in die for-Schleife ziehen, einen Dateinamen erzeugen und ``liste[start:start+block_size]`` schreiben. Der Code steht schon beinahe da.
Das Leben ist wie ein Tennisball.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Sorry,
dass ich hier immer wieder meine wilden Skripte (Skriptfetzen) poste, aber ich mag auch nicht Altes gravierend ändern, falls es jemand gerade kommentiert. Dann wird der Post ja sinnfrei und nicht mehr nachvollziehbar für spätere Leser. Oder sehe ich es falsch?

Code: Alles auswählen

# -*- coding: utf-8 -*-
import csv, os, sys

datei = 'C:/Skripttesten/scripttest/test/test.csv' # relevanter Pfad mit Dateien
liste = []
block_size = 3
i=0
with open(datei, 'rb') as f:
   reader = csv.reader(f)

   for row in reader: # unglücklichst zum einlesen ein csv in eine Liste
      liste.append(row) # unglücklichst zum einlesen ein csv in eine Liste

   for start in range(0, len(liste), block_size):
      i=i+1
      einzeldatei = open('C:/Skripttesten/scripttest/test/Test2/Teil' + str(i) +'.csv', 'wb')
      writer = csv.writer(einzeldatei).writerows(liste[start:start+block_size])   
print ("Fertig. CSV ist in " + str(i) + " grosse Stuecke mit jeweils " + str(block_size) + " Zeile zerlegt")
VG
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

kidchino hat geschrieben:Sorry,
dass ich hier immer wieder meine wilden Skripte (Skriptfetzen) poste, aber ich mag auch nicht Altes gravierend ändern, falls es jemand gerade kommentiert. Dann wird der Post ja sinnfrei und nicht mehr nachvollziehbar für spätere Leser. Oder sehe ich es falsch?
Das siehst du richtig.

Deinen Code kannst du noch etwas verbessern:

Code: Alles auswählen

import csv

QUELLE = 'C:/Skripttesten/scripttest/test/test.csv'
ZIEL = 'C:/Skripttesten/scripttest/test/Test2/Teil{}.csv'
BLOCK_GROESSE = 3

def main():
    with open(QUELLE, "rb") as fp:
        daten = list(csv.reader(fp))

    for index, start in enumerate(range(0, len(liste), BLOCK_GROESSE)):
        with open(ZIEL.format(index), "wb") as output:
            csv.writer(output).writerows(daten[start:start+BLOCK_GROESSE])

if __name__ == "__main__":
    main()
Das Leben ist wie ein Tennisball.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hey,
ich glaube es klappt so!
Seht ihr noch fiese Fehler, die die Funktion stören könnten?

Nicht wichtig aber interessant: Wie kann ich im letzten Print-Befehlt die Umlaute richtig schreiben oder geht das gar nicht?

LG
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

@Eydu:
EyDu hat geschrieben:Deinen Code kannst du noch etwas verbessern:
Leider kommt ich mit Deinem Code nicht richtig klar.
Bei mir kommt immer der Fehler:

Code: Alles auswählen

NameError: global name 'liste' is not defined
Und muss einmal "list" und einmal "liste" dort stehen?

VG
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

@EyDu
Ha,
Du wolltest mich wahrscheinlich testen ;)

Das "Liste" müsste Daten "heißen" in Deiner Zeile 11.

Vielen Dank für Hilfe und Motivation!
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@kidchino: Und jetzt noch ein bißchen umschreiben, und dann kann die Datei auch beliebig groß werden.

Code: Alles auswählen

import csv
from itertools import groupby, count
 
QUELLE = 'C:/Skripttesten/scripttest/test/test.csv'
ZIEL = 'C:/Skripttesten/scripttest/test/Test2/Teil{0:04d}.csv'
BLOCK_GROESSE = 3
 
def main():
    with open(QUELLE, "rb") as fp:
        daten = csv.reader(fp)
        for index, rows in groupby(daten, lambda _, w=count(): next(w)//BLOCK_GROESSE):
            with open(ZIEL.format(index), "wb") as output:
                csv.writer(output).writerows(rows)
 
if __name__ == "__main__":
    main()
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi
Danke auch Dir Sirius3 und natürlich auch dem Rest hier!

Das hier geht dann aber nicht mehr oder?
print ("Fertig. CSV ist in " + str(index) + " grosse Stuecke mit jeweils " + str(BLOCK_GROESSE) + " Zeilen zerlegt")
Nicht, dass es essentiell wichtig wäre, aber ein nicetohave. Kann ich den index irgendwie mit den Print am Ende packen?
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

kidchino hat geschrieben:Das hier geht dann aber nicht mehr oder?
print ("Fertig. CSV ist in " + str(index) + " grosse Stuecke mit jeweils " + str(BLOCK_GROESSE) + " Zeilen zerlegt")
Wieso sollte das nicht gehen? Python kennt Sichtbarkeitsgrenzen nur bezogen auf Funktionen und Methoden. `index` kann also nach dem kompletten Durchlaufen der Schleife immer noch weiterverwendet werden, sofern du dachtest, es wäre dann nicht mehr erreichbar. Oder meintest du etwas anderes?
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Skripttesten\Python_Skripte\csv_splitten.py", line 19, in <module>
    print ("Fertig. " + QUELLE +" ist in "+index+ " CSVs  ist jeweils " + str(BLOCK_GROESSE) + " Zeilen zerlegt")
NameError: name 'index' is not defined
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Das kann eigentlich nur sein, wenn die Schleife 0-mal durchlaufen wird. Dann wird `index` nämlich nicht angelegt (sofern es noch nicht vorhanden war). Zum Vergleich mal eine Sitzung aus der Python-Shell:

Code: Alles auswählen

>>> for index in range(0):
...     print('foo')
...
>>> print(index)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'index' is not defined
>>> for index in range(3):
...     print('foo')
...
foo
foo
foo
>>> print(index)
2
Das ist etwas gewöhnungsbedürftig, wenn man es von anderen Sprachen her anders kennt. Aber so funktioniert Python nunmal.
Antworten