2014-01-19 3 views
1

В F # есть способ сопоставить, например, [2;2;2;2;5;5;5;7;7], с [4,3,2] без рекурсии и без изменения? Я просмотрел элементы Array и List и нашел «Уменьшить», но это, похоже, не помогает.F # подсчет повторений в списке

+0

Почему рекурсия и изменяемое ограничение? Я мог бы вытащить петлю за цикл и ячейку ref, но это не принципиально другое. – JaredPar

+0

Я думал, что будет чище и короче. Не уверен, что вы подразумеваете под «но это не принципиально другое». –

+2

Просто nitpicking, но '[4,3,2]' является кортежем - я думаю, вы имели в виду '[4; 3; 2]' :) –

ответ

4

Попробуйте это:

[2;2;2;2;5;5;5;7;7] |> Seq.groupBy id |> Seq.map (snd >> Seq.length) 

Seq.groupBy id собирает список на группы одинаковых элементов - с помощью функции идентичности id означает, что элементы последовательности используются непосредственно в качестве «ключей» для проверки равенства. Это дает нам последовательность исходных элементов спаренных с повторениями:

seq [(2, seq [2; 2; 2; 2]); (5, seq [5; 5; 5]); (7, seq [7; 7])] 

Тогда для каждого из внутренних последовательностей, мы используем snd только получить последовательность повторов, и Seq.length, чтобы получить его длину. >> - оператор композиции, который применяет первую функцию, а затем вторую.

+0

Brilliant - спасибо! –

11

Вы можете реализовать его быстро, используя Seq.countBy. Использование F # интерактивным, он выглядит следующим образом:

> [2;2;2;2;5;5;5;7;7] |> Seq.countBy id;; 
val it : seq<int * int> = seq [(2, 4); (5, 3); (7, 2)] 

Если вы хотите только счетчики (а не значения, которые повторяются), вы можете просто труба результат в Seq.map:

> [2;2;2;2;5;5;5;7;7] |> Seq.countBy id |> Seq.map snd;; 
val it : seq<int> = seq [4; 3; 2] 

Обратите внимание, что вы можете реализовать это с помощью Seq.groupBy, но Seq.countBy намного эффективнее: Seq.groupBy потребляет больше памяти, потому что он должен хранить все группы, тогда как Seq.countBy хранит только один int (счетчик) для каждой клавиши в последовательности.

Смежные вопросы