Как читать строки с последней по первую?

#python #csv

#python #csv

Вопрос:

Я хочу читать строки с последней по первую. Но я не могу этого сделать. Я хочу читать в обратном порядке.

 stary_patient_2 ='Xs'
nowy_patient_2 = 'VB'
import csv
with open(DATA_DIR '/stage_2_train_labels_right.csv', 'r') as inp, open(DATA_DIR '/stage_2_train_labels_right_poprawne.csv', 'w') as out:
    reader = csv.DictReader(inp, delimiter=' ',fieldnames = ['patientId','x', 'y', 'width', 'height', 'Target'])
    writer = csv.DictWriter(out, fieldnames=reader.fieldnames)
    writer.writeheader()
    for row in reversed(list(open(DATA_DIR '/stage_2_train_labels_right.csv'))):
        nowy_patient_2 = row[0]
        print(row)
        print(row[5])
        if not (row[5]=='0' and nowy_patient_2==stary_patient_2):
            writer.writerow({'patientId': row[0], 'x': row[1], 'y': row[2], 'width': row[3], 'height': row[4], 'Target': row[5]})

    stary_patient_2 = nowy_patient_2 
  

входной файл:

 asdasd 1 2 3 4 5
dddddd 2 2 2 2 2
cccccc 3 2 5 6 1
  

вывод

 cccccc 3 2 5 6 1
dddddd 2 2 2 2 2
asdasd 1 2 3 4 5
  

Ответ №1:

 for row in reversed(list(open(DATA_DIR '/stage_2_train_labels_right.csv'))):
  

это не сработает, потому что вы снова открываете входной файл, а затем передаете не csv объект, а дескриптор файла.

Просто преобразуйте reader в list , чтобы полностью прочитать файл, затем вы можете применить reversed к списку строк.

 with open(os.path.join(DATA_DIR,'stage_2_train_labels_right.csv'), newline="") as inp, open(os.path.join(DATA_DIR,'stage_2_train_labels_right_poprawne.csv'), 'w', newline="") as out:
    reader = csv.DictReader(inp, delimiter=' ',fieldnames = ['patientId','x', 'y', 'width', 'height', 'Target'])
    writer = csv.DictWriter(out, fieldnames=reader.fieldnames)
    # read input file fully into a list of rows
    reader = list(reader)
    writer.writeheader()
    # now iterate on reversed list
    for row in reversed(reader):
  

Ответ №2:

Я не уверен, что это действительно возможно при чтении из файла. Файл считывается с помощью указателя файла, который указывает на начало файла. При перемещении указателя байт, на который вы смотрите, также изменяется — на самом деле у вас нет всего объекта в памяти, и поэтому вы не можете его отменить. Если вы действительно хотите, чтобы это было наоборот, вам, вероятно, нужно будет читать байт за байтом, постоянно возвращая один байт, а не строку за строкой. Итак, не зная точно, как будет сформирован файл, вот как может выглядеть read_last_line:

 def read_last_line(path):
  buffer = []
  with open(path, 'r') as fh:  # this might be easier not using with
    fh.seek(0, os.SEEK_END) # read last byte
    size = fh.tell()
    r_pos = -1
    while True:
      fh.seek(size   r_pos, 0)
      ch = fh.read(1)
      r_pos -= 1
      if ch == 'n':
        return list(reversed(buffer))
      else:
        buffer.append(ch)
  

Однако с этим есть проблемы: очевидно, что он получает только последнюю строку. Вам нужно будет адаптировать это для итерации по файлу. Во-вторых, он считывает файл на один байт за раз, что может быть проблемой. В-третьих, он возвращает список, когда вам может понадобиться что-то еще. и т.д. и т.п. Это не идеально.

Вот две альтернативы:

  1. Если у вас есть свободная память, вы можете просто прочитать весь файл целиком, разбить его на новые строки, а затем изменить это, чтобы получить тот же эффект, который вы хотите. Но если файлы слишком большие, то это будет проблемой.
  2. Если у вас есть контроль над файлом, вы можете либо записать его в обратном порядке, либо выполнить операцию чтения из файла и самостоятельно преобразовать его в новый файл. Это странно, поэтому менее идеально, но это может решить вашу проблему, если вы сможете записать другую версию этого файла на диск.

Комментарии:

1. У любого такого решения есть другая проблема с CSV, в частности: обычное определение строки не применяется к CSV. Вам необходимо учитывать кавычки / экранирование и определенный разделитель записей (например, простой n может не быть новой строкой, только с rn подсчетом).

2. Очень верно, и это применимо к любому формату, чьи «строки» не обязательно разделяются символом новой строки. Но вы столкнетесь с одной и той же проблемой, идущей вперед и назад. т. Е. в любом случае вам нужно будет адаптировать приведенный здесь код, чтобы он был полезен для вашей проблемной области.

3. Работа с пересылкой в порядке, csv модуль знает, как со всем этим справиться. Работая в обратном направлении, csv модуль не может помочь, и вы застряли, переопределяя его с нуля, но в обратном направлении, что делает его еще более безумным.