Я пытаюсь разобрать CSV-файл большого размера в J, и вот маршрутизация с разделением строк, которую я придумал:
splitlines =: 3 : 0
NB. y is the input string
nl_positions =. (y = (10 { a.)) NB. 1 if the character in that position is a newline, 0 otherwise
nl_idx =. (# i.@#) nl_positions NB. A list of newline indexes in the input string
prev_idx =. (# nl_idx) {. 0 , nl_idx NB. The list above, shifted one position to the right, with 0 as the first element
result =. ''
for_i. nl_idx do. NB. For each newline
to_drop =. i_index { prev_idx NB. The number of characters from the start of the string to skip
to_take =. i - to_drop NB. The number of characters in the current line
result =. result , < (to_take {. to_drop }. y) NB. Take the current line, box it and add to the result
end.
)
Хотя это действительно медленно. Монитор производительности показывает, что строка 8 занимает больше всего времени, вероятно, из-за выделения всей памяти при удалении и извлечении элементов и расширении списка результатов:
Time (seconds)
┌────────┬────────┬─────┬─────────────────────────────────────────┐
│all │here │rep │splitlines │
├────────┼────────┼─────┼─────────────────────────────────────────┤
│0.000011│0.000011│ 1│monad │
│0.003776│0.003776│ 1│[1] nl_positions=.(y=(10{a.)) │
│0.012429│0.012429│ 1│[2] nl_idx=.(#i.@#)nl_positions │
│0.000144│0.000144│ 1│[3] prev_idx =.(#nl_idx){.0,nl_idx │
│0.000002│0.000002│ 1│[4] result=.'' │
│0.027566│0.027566│ 1│[5] for_i. nl_idx do. │
│0.940466│0.940466│20641│[6] to_drop=.i_index{prev_idx │
│0.011238│0.011238│20641│[7] to_take=.i-to_drop │
│4.310495│4.310495│20641│[8] result=.result,<(to_take{.to_drop}.y)│
│0.006926│0.006926│20641│[9] end. │
│5.313052│5.313052│ 1│total monad │
└────────┴────────┴─────┴─────────────────────────────────────────┘
Есть лучший способ сделать это? Я ищу способ:
- Разрезать список без выделения памяти
- Может быть, заменить весь цикл
for
одной инструкцией по массиву