Python losowe N linii z dużego pliku (bez duplikatów linii)
Muszę użyć pythona do pobrania N liczby linii z dużego pliku txt. Te pliki są w zasadzie tabelami rozdzielanymi tabulatorami. Moje zadanie ma następujące ograniczenia:
Pliki te mogą zawierać nagłówki (niektóre mają nagłówki wieloliniowe).Nagłówki muszą pojawiać się na wyjściu w tej samej kolejności.Każda linia może być wykonana tylko raz.Największy plik ma obecnie około 150 GB (około 60 000 000 linii).Linie są mniej więcej tej samej długości w pliku, ale mogą się różnić między różnymi plikami.Zwykle biorę 5000 losowych linii (mogę potrzebować do 1 000 000 linii)Obecnie napisałem następujący kod:
inputSize=os.path.getsize(options.input)
usedPositions=[] #Start positions of the lines already in output
with open(options.input) as input:
with open(options.output, 'w') as output:
#Handling of header lines
for i in range(int(options.header)):
output.write(input.readline())
usedPositions.append(input.tell())
# Find and write all random lines, except last
for j in range(int(args[0])):
input.seek(random.randrange(inputSize)) # Seek to random position in file (probably middle of line)
input.readline() # Read the line (probably incomplete). Next input.readline() results in a complete line.
while input.tell() in usedPositions: # Take a new line if current one is taken
input.seek(random.randrange(inputSize))
input.readline()
usedPositions.append(input.tell()) # Add line start position to usedPositions
randomLine=input.readline() # Complete line
if len(randomLine) == 0: # Take first line if end of the file is reached
input.seek(0)
for i in range(int(options.header)): # Exclude headers
input.readline()
randomLine=input.readline()
output.write(randomLine)
Ten kod wydaje się działać poprawnie.
Wiem, że ten kod preferuje linie, które podążają za najdłuższymi liniami na wejściu, ponieważ seek () najprawdopodobniej zwróci pozycję na najdłuższej linii, a następny wiersz zostanie zapisany na wyjściu. Nie ma to znaczenia, ponieważ linie w pliku wejściowym są mniej więcej tej samej długości. Wiem też, że ten kod powoduje nieskończoną pętlę, jeśli N jest większe niż liczba linii w pliku wejściowym. Nie zaimplementuję tego sprawdzenia, ponieważ uzyskanie liczby linii zajmuje dużo czasu.
Ograniczenia pamięci RAM i HDD są nieistotne. Martwię się tylko szybkością programu. Czy istnieje sposób na dalszą optymalizację tego kodu? A może jest lepsze podejście?
EDYTOWAĆ: Aby wyjaśnić, linie w jednym pliku mają mniej więcej tę samą długość. Mam jednak wiele plików, które ten skrypt musi uruchomić, a średnia długość linii będzie inna dla tych plików. Na przykład plik A może mieć ~ 100 znaków na linię i plik B ~ 50000 znaków w linii. Nie znam wcześniej średniej długości linii żadnego pliku.