#python
#python
Вопрос:
У меня есть небольшой вопрос. У меня есть файл в следующем формате:
1 2
1 2 3
1 2
1 2 3 4
2 4
Значения в коде на самом деле представляют числа (не обязательно однозначные), но они могут быть любыми числами, также могут быть значениями с плавающей запятой.
Входной файл: Для конкретной строки каждое число отделено от другого одним пробелом (разделителем не может быть ничего, кроме пробела).
Моя задача: Я хочу нулевое заполнение пустых мест таким образом, чтобы это выглядело следующим образом, т. Е. заполнить пустые места таким образом, чтобы это дало мне приятный формат, похожий на матрицу:
1 2 0 0
1 2 3 0
1 2 0 0
1 2 3 4
2 4 0 0
Выходной файл: Применяется то же правило. Для конкретной строки каждое число отделяется от другого только одним пробелом.
Используемый язык: Python (или может быть Shell, если это возможно)
Я знаю, что есть такая функция, которая называется zfill, но я не думаю, что это сильно помогло бы мне.
Мое решение: найдите (максимальную длину / 2) каждой строки, используя функции len и max. Затем, используя split(), заполните нулями соответствующие места каждой строки. Я боюсь, что это может превратиться в грязный код, и я уверен, что есть лучшие способы выполнить эту задачу.
Любое предложение приветствуется.
Спасибо!
Комментарии:
1. все ли числа в файлах однозначные?
2. Вам нужно быть более конкретным. Действительно ли значения
1
,2
3
,4
,,,,,,,,,,, на самом деле представляют числа (т. Е. Они могут быть любыми), или они являются каким-то символом, концептуально обрабатываемым как символ (т. Е. Это всегда будет только одна цифра каждое)? Может ли пробел во входных данных, разделяющий их, быть чем-то иным, кроме пробелов? Имеет ли значение, как они расположены в выходном файле?3. @Karl Knechtel: Я попытался ответить на ваши вопросы, обновив свой первоначальный вопрос. Пожалуйста, дайте мне знать, если вам нужны дополнительные сведения.
Ответ №1:
Предположим, myfile
это открытый файл. Мы используем izip_longest из itertools для перебора столбцов входного файла, заполняя "0"
отсутствующие значения:
[('1', '1', '1', '1', '2'), ('2', '2', '2', '2', '4'),
('0', '3', '0', '3', '0'), ('0', '0', '0', '4', '0')]
Затем мы просто снова заархивируем этот вывод, чтобы восстановить строки с заполненными нулями. Это код:
from itertools import izip_longest
rows = [line.split() for line in myfile] # Read
rows = zip(*izip_longest(*rows, fillvalue="0")) # Add zeroes
print "n".join(" ".join(row) for row in rows) # Write
РЕДАКТИРОВАТЬ: приведенное выше (имхо элегантное) решение немного медленнее (8,55 usec против 7,08 usec), чем наивный подход:
rows = [line.split() for line in myfile]
maxlen = max(len(x) for x in rows)
for row in rows:
print " ".join(row ["0"] * (maxlen - len(row)))
Повторный комментарий
Если вы хотите выровнять столбцы, проще всего изменить первый подход, потому что там у нас уже есть числа, упорядоченные по столбцам в одной точке. Это упрощает поиск ширины столбца.
from itertools import izip_longest
rows = [line.split() for line in myfile]
columns = list(izip_longest(*rows, fillvalue="0"))
column_width = [max(len(num) for num in col) for col in columns]
# We make a template of the form "{0:>a} {1:>b} {2:>c} ...",
# where a, b, c, ... are the column widths:
column_template = "{{{0}:>{1}s}}"
row_template = " ".join(column_template.format(i, n) for
i, n in enumerate(column_width))
print "n".join(row_template.format(*row) for row in zip(*columns))
Комментарии:
1. Спасибо. Если я не ошибаюсь, ваше решение кажется прекрасным, если столбцы представляют собой однозначные числа. Но, как я уже упоминал, в этом нет необходимости. Если во входном файле есть двузначное / многозначное число в любом из его столбцов, выходные данные, которые предоставляет ваш код, довольно беспорядочные, т. Е. они не находятся (или, скорее, не начинаются / заканчиваются) в одном столбце. Подумайте об этом так: выходные данные, следовательно, сгенерированные, берутся как матрица для дальнейших матричных операций. Для меня это не проблема, поскольку genfromtxt, похоже, позаботится об этом (по крайней мере, на данный момент). Итак, я поднимаю это только для целей обсуждения
2. Позвольте мне процитировать вам ваш вопрос: «Выходной файл: применяется то же правило. Для конкретной строки каждое число отделяется от другого только одним пробелом «. Вы передумали?
3. Да, я виноват. Посмотрев на вывод многозначных столбцов, мне пришлось изменить свое мнение.
Ответ №2:
Вы всегда можете прочитать каждую строку и посчитать количество чисел, которые у вас есть. Затем вы можете записать эту строку в новый временный файл и добавить заполнения после, и вы можете перезаписать исходный файл этим временным файлом, если требуется.
Чтобы подсчитать количество чисел, которые вы можете использовать str.split()
с вашим символом пробела в качестве разделителя, вы просто получаете количество записей в списке. Добавление вашего номера заполнения должно быть довольно простым.
Ответ №3:
Что-то вроде этого — но я также считаю, что его следует обновить, поскольку в вашем вопросе не все ясно:
tst="""
1 2
1 2 3
1 2
1 2 3 4
2 4
"""
res = [line for line in tst.split('n') if line != '']
mLen = max(len(line) for line in res)
print 'n'.join(list((line ' 0' * ((mLen - len(line))//2) for line in res)))
Комментарии:
1. Вам не нужно использовать
list
в последней строке:'n'.join(line ' 0' * ((mLen - len(line))//2) for line in res)
2. @lazyr Конечно, моя ошибка — просто забыл удалить его перед публикацией (играл с итераторами).
3. Спасибо. Если я не ошибаюсь, ваше решение кажется прекрасным, если столбцы представляют собой однозначные числа. Но, как я уже упоминал, в этом нет необходимости. Если во входном файле есть двузначное / многозначное число в любом из его столбцов, выходные данные, которые предоставляет ваш код, довольно беспорядочные, т. Е. они не находятся (или, скорее, не начинаются / заканчиваются) в одном столбце. Подумайте об этом так: выходные данные, следовательно, сгенерированные, берутся как матрица для дальнейших матричных операций. Для меня это не проблема, поскольку genfromtxt, похоже, позаботится об этом (по крайней мере, на данный момент). Итак, я поднимаю это только для целей обсуждения