Вопрос плохо определен, но если предположить, что OP хочет получить результат, показанный в примере DataFrame (то есть не только последняя строка каким-то образом украшена именем файла, но все строки), здесь есть способ добиться этого. Для этого примера у нас есть только два файла: file1.txt
содержит две строки: «a» и «b», file2.txt
содержит одну строку: «c».
Мы пишем средство чтения файлов, которое возвращает список списков: каждый подсписок содержит имя файла и строку.
import glob
def get_file(filename):
with open(filename) as f:
return [[filename, line.rstrip('\n')] for line in f]
Попробуйте:
m = map(get_file, glob.glob('file*.txt'))
list(m)
Out[]:
[[['file2.txt', 'c']], [['file1.txt', 'a'], ['file1.txt', 'b']]]
Давайте сгладим эти списки, чтобы получить один двумерный массив. Кроме того, вероятно, лучше получить результат, когда файлы отсортированы в алфавитном порядке.
def flatten(m):
return [k for sublist in m for k in sublist]
m = map(get_file, sorted(glob.glob('file*.txt')))
flatten(m)
Out[]:
[['file1.txt', 'a'], ['file1.txt', 'b'], ['file2.txt', 'c']]
Теперь иногда полезно иметь номер строки (например, если мы собираемся поместить эти данные в DataFrame и выполнить дальнейшую сортировку и аналитику). Наш читатель становится:
def get_file(filename):
with open(filename) as f:
return [[filename, lineno, line.rstrip('\n')] for lineno, line in enumerate(f, start=1)]
m = map(get_file, sorted(glob.glob('file*.txt')))
out = pd.DataFrame(flatten(m), columns=['filename', 'lineno', 'line'])
out
Out[]:
filename lineno line
0 file1.txt 1 a
1 file1.txt 2 b
2 file2.txt 1 c
Обратите внимание, что вышеприведенный map
прекрасно подходит для многопоточного чтения, если у нас есть большое количество файлов:
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=4) as pool:
m = pool.map(get_file, sorted(glob.glob('file*.txt')))
out = pd.DataFrame(flatten(m), columns=['filename', 'lineno', 'line'])
out
Out[]:
filename lineno line
0 file1.txt 1 a
1 file1.txt 2 b
2 file2.txt 1 c
Обратите внимание, что это может быть длинным, чтобы проверить, все ли ключи являются числами перед преобразованием...
def array_from_hash(h)
return h unless h.is_a? Hash
all_numbers = h.keys.all? { |k| k.to_i.to_s == k }
if all_numbers
h.keys.sort_by{ |k| k.to_i }.map{ |i| array_from_hash(h[i]) }
else
h.each do |k, v|
h[k] = array_from_hash(v)
end
end
end
Если мы сможем Предположим, что все ключи на самом деле являются строками, которые конвертируются чисто в целые числа, должно работать следующее:
# "hash" here refers to the main hash in your example, since you didn't name it
stuff_hash = hash["stuff"]
hash["stuff"] = stuff_hash.keys.sort_by {|key| key.to_i}.map {|key| stuff_hash[key]}