Как из текстового файла БЫСТРО создать заданное количество файлов с заданным количеством строк Python?

Интересует самая оптимальная методика решения такой задачи на Python (оптимальность определяется скоростью выполнения всех итераций)

Входные данные: указываем текстовый файл с большим количеством строк (количество неизвестно), нуказываем файл со строками-названиями подпапки и сколько в исходящих файлах должно быть строчек (задается не четкое число, а минимум и максимум)

В итоге скрипт должен самым быстрым способом сделать количество файлов (количество равно количество строк файла со строками-названиями) с одинаковым именем и распихать их по папкам (имя папки брать из текущей строки-названия). Важно: в исходящем файле строки не должны повторяться (одна строка уникальна на весь файл).

Например: есть файл names.txt (в нём 1 000 000 строк), есть файл cities.txt
Содержимое файла cities.txt:
Москва
Абакан
Тверь
Питер

Мы указываем эти два файла и говорим, что должно быть от 1000 до 1200 строк.

На выходе получаем папки: Москва, Абакан, Тверь, Питер в каждой из которых есть файл name.txt в котором содержится от 1000 до 1200 уникальных внутри файла строк, которые взяты из файла names.txt ПРОИЗВОЛЬНО
  • Вопрос задан
  • 3416 просмотров
Пригласить эксперта
Ответы на вопрос 2
@kascode
На мой взгляд лучшим решением будет прочитать большой файл names.txt в list и, соответственно, держать его в памяти.

Ну а дальше дело техники. Читаем построчно файл с городами. Для каждого города создаём папку с соответствующим именем. В папке файл name.txt. В него осуществяем построчную запись случайной строки из исходного файла с проверкой на дублирование.

Структуру файла cities.txt я принял такую: [город]|[количество строк для города]
москва|1000
санкт-петербург|1100

__author__ = 'kascode'
from random import randint
import os

source = open('names.txt', 'r')

sourcelines = source.readlines()
sourcelineslen = len(sourcelines)

def readCities():
    with open('cities.txt', 'r') as f:
        citylines = f.readlines()

    citieslist = []
    
    # заполняем список данными в формате [['город'], ['число строк']] 
    for line in citylines:
        citieslist.append(line.split('|'))

    return citieslist

for city in readCities():
    # создаём папку с именем города
    if not os.path.exists(city[0]):
        os.makedirs(city[0])

    file = city[0] + '/name.txt'
    cityout = open(file, 'w')
    written = []        # массив записанных строк

    # записываем столько строк, сколько указано для города
    for i in range(1, int(city[1])):
        # берём случайную строку из исходного списка
        sourceline = sourcelines[randint(0, sourcelineslen-1)]
        
        # берём новую пока не найдём не дублирующую
        while sourceline in written:
            sourceline = sourcelines[randint(0, sourcelineslen-1)]

        cityout.write(sourceline)
        written.append(sourceline)


На моей машине обработка файла в 10000000 строк длиной 10-50 символов заняла 0,21с.
Ответ написан
Комментировать
sharlatan
@sharlatan
IT engineer, warehouse operative
Вопрос интересный и если еще актуален.
Был вариант каждый раз смешивать исходный массив данных (текстовый файл с большим количеством строк) и брать случайное количество в заданном промежутке в файл names.txt.
В итоге скрипт просит указать БОЛЬШОЙ файл, файл ИМЕН и ПРОМЕЖУТОК. Создаются папки из файла ИМЕН во временной директории "out_log", в каждый файл случайным образом, без повторов, вносятся строчки из БОЛЬШОГО файла.
Тестировал на машине под Fedora 20 Workstation
CPU Intel(R) Core(TM) i7-3770S CPU @ 3.10GHz
RAM Kingstone KHX1600C10D3/8GX 16Gb Speed: 1333 MHz
OSHDD Intel SSD 520

На обработку списка из Всех городов России и 120,000,000 исходных строках в промежутку 1000-1200 ушло 0.50с

#! /usr/bin/env python
# File:          rndappend.py
#
# Created:       Sat 20 Dec 2014 16:05:30
# Last Modified: Mon 29 Dec 2014 01:21:58
# Maintainer:    sharlatan, <sharlatanus@gmail.com>
# License:       Same as Python (GPL)
# Credits:       www.toster.ru/q/166037
#
"""
-=[ Description
The idea of this script (Scr) is taken from www.toster.ru. We give  to the Scr
file of names.txt (more then 1kk lines, file of cities.txt (up to 100) and
numbert in some range. 
Create files from cities.txt and copy random <lines> from <source> to them.

"""


import os
import sys
from random import randint


LOC_PATH = "out_log"
if not os.path.exists(LOC_PATH):
    os.makedirs(LOC_PATH)


def mk_f(dir_name, stuff):
    # Create <dir_name> in <LOC_PATH> with <names.txt> fild with <stuff>
    path_to_bask = os.getcwd()
    new_path = os.path.join(LOC_PATH, dir_name)
    os.makedirs(new_path)
    os.chdir(new_path)

    with open('names.txt', 'w') as f:
        for c in stuff:
            f.write("%s\n" % c)
        f.close()
    os.chdir(path_to_bask)


def read_f(file_in):
    # Read file and retun list of lines without empty items
    with open(file_in, 'r') as f:
        file_out = f.read().split('\n')
    return file_out[:-1]


def rnd_chunk(into_list, min_piece, max_piece):
    # Return random lines from <into_list> withing given range
    out_list = []
    item_quantity = randint(min_piece, max_piece)
    into_list_len = len(into_list)
    while True:
        if len(out_list) != item_quantity:
            put_in = into_list[randint(0,into_list_len-1)]
            if put_in not in out_list:
                out_list.append(put_in)
        else:
            return out_list


def usage():
    #  Show the usage of the script
    file_name = sys.argv[0]
    print ("""\nIncorrect quantity of arguments given or unexisting files
Usage: %s <source file> <cities file> <lines MIN-MAX>\n""" % file_name)


def main():
    """
    Check arguments, for quantity given, for existence of files, for given
    length of <lines>
    """
    if len(sys.argv) != 4:
        usage()
        quit()
    elif os.path.isfile(sys.argv[1]) != True \
       or os.path.isfile(sys.argv[2]) != True:
        usage()
        quit()

    # Take all varialbe from argv
    GET_PIEACE = sys.argv[3].split("-")
    PIECE_MIN = int(GET_PIEACE[0])
    PIECE_MAX = int(GET_PIEACE[1])
    CITIES = read_f(sys.argv[2])
    SOURCE = read_f(sys.argv[1])

    for city_name in CITIES:
        mk_f(city_name, rnd_chunk(SOURCE, PIECE_MIN, PIECE_MAX))

if __name__ == '__main__':
    main()
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы