Jak rozpoznać koniec pliku

0

Witam
Mam zadanie połączyć dwa pliki tekstowe razem. W pliku znajdują się same wyrazy oddzielone enterem. Wynikiem ma być trzeci plik tekstowy. O ile jest to proste to trudność polega na tym że w pliku trzecim nie ma być powtórzeń. Więc wymyśliłem coś takiego że biorę wyraz z pliku pierwszego i szukam go w pliku końcowym. Jeśli go tam nie ma to ma dopisać. Jeśli się znajduje to ma wsiąść kolejny wyraz i znowu szukać.
Napisałem już coś takiego:

def read():
    with open('slowo.txt') as reader:
        for slowo in reader:
            yield slowo
def write():
    with open('dictionary.txt', 'r') as writer:
        for slowo2 in writer:
            yield slowo2

for read1 in read():
    for read2 in write():
        #print(read1.strip() + ' oraz ' + read2.strip())
        if read1.strip() == read2.strip():
            print('słowo już jest: '+ read1.strip())
            break
        if read1.strip() != read2.strip():
            pass


Zatrzymałem się na tym że skąd program ma wiedzieć że dotarł do końca pliku żeby mógł podjąć decyzję że słowa brakuje. Czy jest inne rozwiązanie tego zagadnienia niż te które wymyśliłem.

0

Gdy dotrzesz do końca pliku, skończą się wartości do yieldowania i pętla się zakończy. Możesz więc zastosować po prostu jakąś flagę - przed pętlą ustawiasz sobie zmienną powtorzone = False, gdy wykryjesz powtórzenie robisz powtorzone = True; break, a po zakończeniu pętli sprawdzasz wartość zmiennej. Nie ma powtórzenia, można dopisać.

1

Lepiej wczytać te pliki do struktur, (tutaj polecane zbiory) i na nich sprawdzić powtórzenia.

0

@lion137: Z tym wczytywaniem jest problem bo pliki na których będę pracował mają po 3 miliony pozycji. Nie mam tyle ramu :D

0

Pół gigabajta pamięci nie Masz?

0

Wczytaj sobie pliki fragmentami używając jakiegoś bufora żeby nie tracić niepotrzebnie pamięci.
Zrób sobie słownik - słowo -> ilość wystąpień. Po przeprocesowaniu pliku nr 1 i 2 do pliku nr 3 wrzuć tylko te słowa gdzie liczba wystąpień wynosi 1

0

Posortowane?

0
Masteratom napisał(a):

@lion137: Z tym wczytywaniem jest problem bo pliki na których będę pracował mają po 3 miliony pozycji. Nie mam tyle ramu :D

3 miliony ale unikalnych? Jeżeli faktycznie większość to powtórzenia to spokojnie możesz użyć np. set do zebrania danych z 1 i 2 pliku (tylko uwaga na kolejność, nie jest zachowana przy secie).

Przy Twoim rozwiązaniu pamiętaj, że wydajność będzie bardzo niska (rzędu O(n^2)). A odpowiadając na pytanie z pierwszego postu - generator zwróci StopIteration więc możesz to przechwycić lub użyć 'else' przy for loopie:

for word in your_generation():
    if word==other_word:
        break
else:
    # if you never used break or your_generation() was empty iterator, it will go to else

0

Nie zależy mi na wydajności. Pliki może skrypt łączyć nawet dwa dni. Program będzie uruchomiony raz i koniec. Usiadłem i napisałem coś takiego i z moich testów wychodzi że to działa.

def merge_file(source, destination = 'dictionary.txt'):
    with open(source, 'r') as word_source:
        for word in word_source:
            duplicate = False
            with open(destination, 'r+') as word_destination:
                for word_dest in word_destination:
                    if word.strip() == word_dest.strip():
                        duplicate = True
                if duplicate == False:
                    word_destination.write(word)


merge_file('slowo.txt')
0

Daj chociaż break po znalezieniu duplikatu, i jak pisałem skorzystaj z else aby zapisać plik. Lub używaj flagi ale z breakiem, aby nie iterować niepotrzebnie 100k linijek jak duplikat został znaleziony w pierwszej.

1

Hmm.. Nie wiem czy dobrze zrozumiałem problem. Ale naprawdę nie wystarczy przecięcie zbioru? Testowałem na RasPi (bo miałem pod ręką) i słownikach po 4 mln. słów. Czas wykonania (wraz z wydrukiem), 6 s.

s1 = {word for word in open("slowo.txt")}
s2 = {word for word in open("dictionary.txt")}
s3 = s1.intersection(s2)
print(s3)

PS. Oczywiście uproszczone bo nie bawiłem się w podziały na wyrazy...

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