Чтение всех символов в OCaml слишком медленное
Я новичок в OCaml, и я хочу прочитать строки из файла, а затем изучить все символы в каждой строке. В качестве фиктивного примера предположим, что мы хотим подсчитать вхождения символа "A" в файл.
Я попробовал следующее
open Core.Std
let count_a acc string =
let rec count_help res stream =
match Stream.peek stream with
| None -> res
| Some char -> Stream.junk stream; if char = 'A' then count_help (res+1) stream else count_help res stream
in acc + count_help 0 (Stream.of_string string)
let count_a = In_channel.fold_lines stdin ~init:0 ~f:count_a
let () = print_string ((string_of_int count_a)^"\n"
Я собираю это с
ocamlfind ocamlc -linkpkg -thread -package core -o solution solution.ml
запустить его с
$./solution < huge_file.txt
на файл с одним миллионом строк, который дает мне в следующий раз
real 0m16.337s
user 0m16.302s
sys 0m0.027s
что в 4 раза больше, чем моя реализация Python. Я вполне уверен, что это должно быть возможно сделать быстрее, но как мне это сделать?
1 ответ
Чтобы посчитать количество символов A в строке, вы можете просто использовать String.count
функция. Действительно, самое простое решение будет:
open Core.Std
let () =
In_channel.input_all stdin |>
String.count ~f:(fun c -> c = 'A') |>
printf "we have %d A's\n"
Обновить
Немного более сложное (и менее требовательное к памяти решение) с [fold_lines] будет выглядеть так:
let () =
In_channel.fold_lines stdin ~init:0 ~f:(fun n s ->
n + String.count ~f:(fun c -> c = 'A') s) |>
printf "we have %d A's\n"
Действительно, он медленнее, чем предыдущий. На моем 8-летнем ноутбуке требуется 7,3 секунды, чтобы посчитать букву "А" в 20-мегабайтном текстовом файле. И 3 секунды на прежнее решение.
Кроме того, вы можете найти этот пост интересным, я надеюсь.