Podwójny for nie wykonuje się do końca.

0

Witam, potrzebuję pomocy z programem.
Mam dane w różnych plikach, które one mają wspólne ID - (kolumna 0)
Program ma wczytać te 2 pliki i utworzyć 3 w którym:
rekordy będą połączone jeśli mają takie same ID.
NP:

plik1 z nagłówkami:
ID;Var1
1;a
2;b
3;c
4;d

plik 2:
ID;Var2
5;5
4;4
7;7
1;1

Oczekiwany output:
ID;Var1;Var2
1;a;1
4;d;4

import csv
file1 = open(r"C:\1.csv")
data1 = csv.reader(file1, delimiter=';')
file2 = open(r"C:\2.csv")
data2= csv.reader(file2, delimiter=';')
csvfile = open(r"C:\output.csv", 'w', newline='')
spamwriter = csv.writer(csvfile, delimiter=';', quoting=csv.QUOTE_MINIMAL)

for var_file1 in data1:                                                                           # biorę jedną linijkę z 1 pliku
    for var_file2 in data2:                                                                       # sprawdzam kolejno wszystkie linijki z 2 pliku
        if var_file1[0] == var_file2[0]:                                                       # jeżeli ID w 2 różnych plikach jest takie samo
            print(var_file1[0], var_file2[0])                                                  # tego właśnie szukałem
            spamwriter.writerow([var_file1[0], var_file1[1], var_file2[1]])    # zapisuję wartości do nowego pliku
            break                                                                                        # znalazłem to co szukałem więc wracam do 1 for
        else:
            print(var_file1[0], var_file2[0])                                                  # wypisuje żeby mieć świadomość tego co robi program

Break, to też dla mnie zagadka. Dodałem go w celu przyśpieszenia programu - tz. jeśli znaleziono parę, to nie ma sensu sprawdzać plik do końca, tylko wracam do pierwszego for.
Czyli z break/czy bez break Output powinien być taki sam, a w cale tak nie jest i tego też nie rozumiem dlaczego tak się dzieje.

Proszę o pomoc,
Program wygląda banalnie prosto i nie rozumiem co robię nie tak.

0

A nie sprawdza czasem tylko dla 1 linijki z pliku pierwszego? Nigdzie nie wracasz na początek pliku, więc przy drugiej stwierdza że w pliku2 nic już nie ma i wraca do pętli 1. Najlepiej chyba będzie otwierać i zamykać plik2 wewnątrz pierwszej pętli

2

Źle do tego podchodzisz. Nie wiem jak duże są te pliki, ale for w forze to słabe rozwiązanie zwiększające czas wykonania programu. Zamiast tego zamień zawartość plików na słowniki i normalnie pobieraj po kluczu. Złożoność obliczeniowa spadnie, kodu będzie mniej i każdy zrozumie od razu co chciałeś osiągnąć.

0

Chcę sprawdzać 1 linijkę pierwszego pliku, następnie po kolei wszystkie linijki drugiego pliku.
Następnie sprawdzam 2 linijkę pierwszego pliku i podstawiam po kolei wszystkie drugiego i tak dalej...
@sig:
Czy dobrze Cię zrozumiałem że ten drugi for nie startuje od początku?
W jaki sposób wrócić na początek? Bo mógłbym ładować plik jeszcze raz, ale w przypadku dużego 1 pliku, zamiast korzystać z tego co mam w pamięci musiałbym ładować to samo tysiąc razy i program by mi to obliczał tydzień czasu.

@siloam
Tak pliki są duże. Słowniki to dla mnie nowość.
W moim przykładzie są 2 kolumny żeby pokazać problem, a w prawdziwych plikach jest kolumn więcej.
Czy słowniki na pewno mają sens?

0

Zdołałem nieco wyizolować problem:

import csv
file1 = open(r"C:\Users\PC\Documents\1.csv")
data1 = csv.reader(file1, delimiter=';')
file2 = open(r"C:\Users\PC\Documents\2.csv")
data2= csv.reader(file2, delimiter=';')
csvfile = open(r"C:\Users\PC\Documents\output.csv", 'w', newline='')
spamwriter = csv.writer(csvfile, delimiter=';', quoting=csv.QUOTE_MINIMAL)

for var_file1 in data1:                                                                                                    # biorę jedną linijkę z 1 pliku
    for var_file2 in data2:                                                                                                # sprawdzam kolejno wszystkie linijki z 2 pliku
        if var_file1[0] == var_file2[0]:                                                                                   # jeżeli ID w 2 różnych plikach jest takie samo
            print(var_file1[0], var_file2[0],"zapis=",var_file1[1],var_file1[2],var_file2[1],var_file2[2])               # tego właśnie szukałem
            #spamwriter.writerow([var_file1[0], var_file1[1], var_file2[1]])                                               # zapisuję wartości do nowego pliku
            break                                                                                                          # znalazłem to co szukałem więc wracam do 1 for

print("2 cześć programu")

data1 = [["ID", "Var1", "Var2"],[1, 1, "a"],[2, 2, "b"],[3, 3, "c"],[4, 4, "d"]]
data2 = [["ID", "Var3", "Var4"],[4, 11, "aa"],[3, 22, "bb"],[2, 33, "cc"],[1, 44, "dd"]]
for var_file1 in data1:                                                                                                    # biorę jedną linijkę z 1 pliku
    for var_file2 in data2:                                                                                                # sprawdzam kolejno wszystkie linijki z 2 pliku
        if var_file1[0] == var_file2[0]:                                                                                   # jeżeli ID w 2 różnych plikach jest takie samo
            print(var_file1[0], var_file2[0],"zapis=",var_file1[1],var_file1[2],var_file2[1],var_file2[2])               # tego właśnie szukałem
            #spamwriter.writerow([var_file1[0], var_file1[1], var_file2[1]])                                               # zapisuję wartości do nowego pliku
            break                                                                                                          # znalazłem to co szukałem więc wracam do 1 for
                                                                                                       # znalazłem to co szukałem więc wracam do 1 for                                                                                                        

Output

ID ID zapis= Var3 Var4 Var3 Var4
1 1 zapis= 1 a 44 dd
2 cześć programu
ID ID zapis= Var1 Var2 Var3 Var4
1 1 zapis= 1 a 44 dd
2 2 zapis= 2 b 33 cc
3 3 zapis= 3 c 22 bb
4 4 zapis= 4 d 11 aa

Dlaczego na plikach csv program ucina obliczenia dla 2,3,4 linii? [licząc od 0]
Wydaję mi się że problem jest właśnie w imporcie danych do listy.

0

W drugim for trzeba resetować iterator seek'em
https://stackoverflow.com/questions/40984797/reset-the-csv-reader-iterator

1

W przypadku bardziej skomplikowanych danych stwórz własny kontener (klasę z metodami do wyszukawania, aktualizowania wartości) lub wykorzystaj gotowe moduły do manipulacji danymi (np. pandas). Jeżeli ID jest unikalne możesz zacząć od użycia wspomnianego słownika. Słownik jest kolekcją unikalnych kluczy (które można zahashować - > muszą być niemutowalne, np. stringi) i wartości np. {'key': [value1, value2]}. Dużą zaletą słowników jest krótki czas na odczytanie danych - dzięki funkcji hashującej jest to O(1) gdzie czytanie z listy wymaganie często przeszukanie całej listy a więc O(n).

Dla danych w csv najpewniej użyłbym pandasa ale można skleić też własne rozwiązanie

# możesz stworzyć dict własnoręcznie:
dictionary = dict()
for row in data:
    dictionary[row[0]] = row[1:]

# później szukanie informacji:
id = 345
if id in dictionary:
    # zapisz do trzeciego pliku (albo lepiej, do tymczasowej listy i zapisz jednorazowo na końcu programu)
0

Dziękuję za pomoc.
Mam jeszczcze problem z zapisaniem tego za jednym zamachem.

input1 = dict()
for row1 in data1:
    input1[row1[0]] = row1[1:]

input2 = dict()
for row2 in data2:
    input2[row2[0]] = row2[1:]

for key in input1:
    if key in input2:
        print(key,input1[key][0],input1[key][1],input1[key][2],input2[key][0],input2[key][1],input2[key][2])
        output[key] = [key,input1[key][0],input1[key][1],input1[key][2],input2[key][0],input2[key][1],input2[key][2]]
spamwriter.writerow([output])

Print jest Ok
Output i zapis do pliku już nie. przede wszystkim to leci jednym ciągiem tz bez enterów...

1

Jeżeli output to też dict, to musisz go przeiterować i odpowiednio zapisać. W twoim przypadku jednak myślę, że nie ma sensu zapisywać output jako dict tylko jako listę rowów do zapisania.
Ale biorąc obecny kod:

for value in output.values():
    spamwrite.writerow(value)

jak chcesz iterować przez klucze i wartości to:

for key, value in output.items():

domyślnie dostajesz tylko klucz:

for key in output:

Opcjonalnie jest spamwrite.writerows() do zapisywania całej kolekcji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1