我有一个整数列表,多次出现的任何整数都会连续出现。我想将它转换为元组列表,包含每个对象及其计数。
我已经提出了下面的内容,但是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
| [] -> []
答案 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