计算列表中元素的出现次数

时间:2011-02-22 21:16:23

标签: f#

我有一个整数列表,多次出现的任何整数都会连续出现。我想将它转换为元组列表,包含每个对象及其计数。

我已经提出了下面的内容,但是temp的返回类型存在问题:“类型'int'与类型''列表'不匹配”。但是,这三种返回类型对我来说是一致的。我做错了什么?如果我所做的不是F#并且应该以完全不同的方式完成,请也让我知道。

let countoccurences list =
    match list with
    | x::xs -> let rec temp list collecting counted =
                    match list with
                    | x::xs when x=collecting -> temp xs collecting counted+1
                    | x::xs -> (collecting,counted)::temp xs x 1
                    | [] -> (collecting,counted)::[]
               temp xs x 1
    | [] -> []

5 个答案:

答案 0 :(得分:25)

编辑:哎呀,这不回答你的问题,因为你说“连续”。但是我会把它留在这里,因为搜索问题标题的人可能会发现它很有用。

Seq.countBy这样做。

let list = [1;2;3;4;5;6;1;2;3;1;1;2]
let results = list |> Seq.countBy id |> Seq.toList 
printfn "%A" results
// [(1, 4); (2, 3); (3, 2); (4, 1); (5, 1); (6, 1)]

答案 1 :(得分:9)

这个怎么样?

lst |> Seq.groupBy (fun x -> x) |> Seq.map (fun (a,b) -> (a, Seq.length(b)))

答案 2 :(得分:4)

在这一行:

| x::xs when x=collecting -> temp xs collecting counted+1

编译器将您的代码解释为

| x::xs when x=collecting -> (temp xs collecting counted)+1

但你想要的是

| x::xs when x=collecting -> temp xs collecting (counted+1)

然而,即使有了这个改变,你的算法的一个问题是temp函数不是尾递归的,这意味着当在长列表上调用时它会导致堆栈溢出(例如{{1在我的机器上失败了)。如果这对您很重要,那么您应该将countoccurences [1..10000]辅助函数重写为尾递归。最简单的方法是添加一个累积的列表参数,然后反转列表。

temp

答案 3 :(得分:1)

我可能会使用一个可变解决方案。也许是这样的:

let countOccurrences l =
    let counts = System.Collections.Generic.Dictionary()
    l |> List.iter (fun x -> 
        match counts.TryGetValue(x) with
        | true, i -> counts.[x] <- i + 1
        | _ -> counts.Add(x, 1))
    counts |> Seq.map (|KeyValue|)

修改

我忘记了countBy(实施方式相同)。

答案 4 :(得分:1)

如果您使用递归来遍历列表,则可以始终使用fold。

let countOccurrences = function
| []    -> []
| x::xs -> ([(x,1)],xs)
           ||> List.fold(fun ((y,c)::acc) x -> if x = y then (y,c+1)::acc else (x,1)::(y,c)::acc) 
           |> List.rev