Вы можете предварительно отсортировать данные после преобразования их в пару пустых массивов.Это позволит вам манипулировать одним ранее существующим буфером, а не копировать строки снова и снова по мере их перераспределения.Разница между моим предложением и вашей попыткой состоит в том, что мы будем использовать ndarray.tobytes
(или ndarray.tostring
) при условии, что у вас есть только символы ASCII.Фактически, вы можете полностью обойти операцию копирования, связанную с преобразованием в bytes
объект, используя ndarray.tofile
напрямую.
Если у вас есть elements
в руке, вы знаете,что общая длина вашей линии будет равна общей длине разделителей табуляции elements
и n-1
.Поэтому начало элемента в полной строке - это его индекс (количество предшествующих ему вкладок) плюс совокупная длина всех элементов, предшествующих ему.Вот простая реализация заполнения одного буфера с использованием в основном циклов Python:
lengths = np.array([len(e) for e in elements])
indices = np.asanyarray(indices)
elements = np.array(elements, dtype='S7')
order = np.argsort(indices)
elements = elements[order]
indices = indices[order]
lengths = lengths[order]
cumulative = np.empty_like(lengths)
cumulative[0] = 0
np.cumsum(lengths[:-1], out=cumulative[1:])
cumulative += lengths
s = np.full(cumulative[-1] + n - 1, '\t', dtype='S1')
for i, l, e in zip(cumulative, lengths, elements):
s[i:i + l].view(dtype=('S', l))[:] = e
Здесь можно поиграть с множеством возможных оптимизаций, таких как возможность выделения s
с использованием np.empty
и заполняются только обязательные элементы вкладками.Это будет оставлено в качестве акциза для читателя.
Другая возможность состоит в том, чтобы полностью не преобразовывать elements
в пустой массив (он, вероятно, просто тратит пространство и время).Затем вы можете переписать цикл for
как
for i, l, o in zip(cumulative, lengths, order):
s[i:i + l].view(dtype=('S', l))[:] = elements[o]
. Вы можете записать результат в объект bytes
с помощью
s = s.tobytes()
ИЛИ
s = s.tostring()
Вы можете записать результат как есть в файл, открытый для двоичной записи.На самом деле, если вам не нужна копия буфера в виде bytes
, вы можете просто записать в файл напрямую:
s.tofile(f)
Это сэкономит вам немного памяти и время обработки.
В том же духе вам может быть лучше просто записать файл напрямую, по частям.Это избавляет вас не только от необходимости выделять полный буфер, но и от суммарной длины.Фактически, единственное, что вам нужно для этого, - это diff
последовательных индексов, указывающих, сколько вкладок нужно вставить:
indices = np.asanyarray(indices)
order = np.argsort(indices)
indices = indices[order]
tabs = np.empty_like(indices)
tabs[0] = indices[0]
np.subtract(indices[1:], indices[:-1], out=tabs[1:])
tabs[1:] -= 1
for t, o in zip(tabs, order):
f.write('\t' * t)
f.write(elements[o])
f.write('\t' * (n - indices[-1] - 1))
Этот второй подход имеет два основных преимущества помимоуменьшенная сумма расчета.Во-первых, он работает с символами Юникода, а не только с ASCII.Во-вторых, он не выделяет никаких буферов, кроме строк вкладок, которые должны быть очень быстрыми.
В обоих случаях сортировка elements
и indices
в порядке возрастания по индексу значительно ускорит процесс.,Первый случай уменьшается до
lengths = np.array([len(e) for e in elements])
indices = np.asanyarray(indices)
cumulative = np.empty_like(lengths)
cumulative[0] = 0
np.cumsum(lengths[:-1], out=cumulative[1:])
cumulative += lengths
s = np.full(cumulative[-1] + n - 1, '\t', dtype='S1')
for i, l, e in zip(cumulative, lengths, elements):
s[i:i + l].view(dtype=('S', l))[:] = e
, а второй становится просто
indices = np.asanyarray(indices)
tabs = np.empty_like(indices)
tabs[0] = indices[0]
np.subtract(indices[1:], indices[:-1], out=tabs[1:])
tabs[1:] -= 1
for t, e in zip(tabs, elements):
f.write('\t' * t)
f.write(e)
f.write('\t' * (n - indices[-1] - 1))