Функция "количество вхождений" Haskell

реализовал count функция в Haskell, и мне интересно, будет ли это плохо вести себя в больших списках:

count   :: Eq a => a -> [a] -> Int
count x =  length . filter (==x)

Я считаю length функция работает в линейном времени, это правильно?

Edit: Рефактор, предложенный @Higemaru

3 ответов


длина выполняется в линейном времени до размера списка, да.

обычно вы беспокоитесь, что ваш код должен пройти два прохода через список: сначала один для фильтрации, а затем один для подсчета длины результирующего списка. Однако я считаю, что здесь этого не происходит, потому что фильтр не строг по структуре списка. Вместо этого функция length заставляет элементы отфильтрованного списка по мере его прохождения выполнять фактический подсчет за один проход.


Я думаю, что вы можете сделать его немного короче

count :: Eq a => a -> [a] -> Int
count x = length . filter (x==)

(Я бы написал (скромный) комментарий, если бы мог)


Это действительно зависит от перечня. Для нормального, лениво оцененного списка Ints на моем компьютере я вижу, что эта функция работает примерно за 2 секунды для 10^9 элементов, 0,2 секунды для 10^8 и 0,3 секунды для 10^7, поэтому она работает в линейном времени. Вы можете проверить это самостоятельно, передав флаги +RTS -s -RTS исполняемому файлу при его запуске из командной строки.

Я также попытался запустить его с большим количеством ядер, но он, похоже, ничего не делает, кроме увеличения памяти использование немного.

дополнительным бонусом ленивых вычислений является то, что вы делаете только один проход по списку. filter и length превратитесь в один цикл компилятором (с включенной оптимизацией), чтобы сохранить память и эффективность.