Чтение всех символов в 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 секунды на прежнее решение.

Кроме того, вы можете найти этот пост интересным, я надеюсь.

Другие вопросы по тегам