F# 用F折叠列表#
我有一个非常琐碎的任务,但我不知道如何使解决方案更漂亮。F# 用F折叠列表#,f#,F#,我有一个非常琐碎的任务,但我不知道如何使解决方案更漂亮。 目标是获取列表并根据结果是否传递谓词返回结果。结果应该分组。下面是一个简化的示例: 谓词:isEven Inp:[2;4;3;7;6;10;4;5] Out:[[^^^^^]..[^^^^^^^]..] 以下是我目前掌握的代码: let f p ls = List.foldBack (fun el (xs, ys) -> if p el then (el::xs, ys) else ([], xs::ys))
目标是获取
列表
并根据结果是否传递谓词返回结果。结果应该分组。下面是一个简化的示例:
谓词:isEven
Inp:[2;4;3;7;6;10;4;5]
Out:[[^^^^^]..[^^^^^^^]..]
以下是我目前掌握的代码:
let f p ls =
List.foldBack
(fun el (xs, ys) -> if p el then (el::xs, ys) else ([], xs::ys))
ls ([], [])
|> List.Cons // (1)
|> List.filter (not << List.isEmpty) // (2)
let even x = x % 2 = 0
let ret =
[2; 4; 3; 7; 6; 10; 4; 5]
|> f even
// expected [[2; 4]; [6; 10; 4]]
让f p ls=
List.foldBack
(fun el(xs,ys)->如果p el那么(el::xs,ys)else([],xs::ys))
ls([],[])
|>列表.Cons/(1)
|>List.filter(非f偶数)
//预期的,预期的
这段代码看起来不太可读。另外,我不喜欢第(1)行和第(2)行。有更好的解决方案吗?这是一个基于递归
列表的递归解决方案。过滤器
let rec _f p ls =
match ls with
|h::t -> if p(h) then
match f p t with
|rh::rt -> (h::rh)::rt
|[] -> (h::[])::[]
else []::f p t
|[] -> [[]]
let f p ls = _f p ls |> List.filter (fun t -> t <> [])
let rec\f p ls=
匹配
|h::t->如果p(h)那么
与f p t匹配
|右::右->(h::右)::右
|[]->(h::[]):[]
else[]::f p t
|[] -> [[]]
让f p ls=_fp ls |>List.filter(fun t->t[])
不过,最后必须进行筛选似乎并不雅致。我想不出一种方法可以使用高阶函数优雅地完成这项工作,但这里有一个解决方案,它使用列表理解。我认为它非常简单易懂
设f p ls=
让rec循环xs=
[将xs与
| [] -> ()
|当px->
let group,rest=collectGroup[x]xs
产量组
让开!休息
|_uxS::xs->yield!loop xs]
和组acc=功能
|x::xs当px->collectGroup(x::acc)xs时
|xs->List.rev acc,xs
环路ls
给你。这个函数也应该有相当好的性能
let groupedFilter (predicate : 'T -> bool) (list : 'T list) =
(([], []), list)
||> List.fold (fun (currentGroup, finishedGroups) el ->
if predicate el then
(el :: currentGroup), finishedGroups
else
match currentGroup with
| [] ->
[], finishedGroups
| _ ->
// This is the first non-matching element
// following a matching element.
// Finish processing the previous group then
// add it to the finished groups list.
[], ((List.rev currentGroup) :: finishedGroups))
// Need to do a little clean-up after the fold.
|> fun (currentGroup, finishedGroups) ->
// If the current group is non-empty, finish it
// and add it to the list of finished groups.
let finishedGroups =
match currentGroup with
| [] -> finishedGroups
| _ ->
(List.rev currentGroup) :: finishedGroups
// Reverse the finished groups list so the grouped
// elements will be in their original order.
List.rev finishedGroups;;
这个怎么样
let folder p l = function
| h::t when p(l) -> (l::h)::t
| []::_ as a -> a
| _ as a -> []::a
let f p ls =
ls
|> List.rev
|> List.fold (fun a l -> folder p l a) [[]]
|> List.filter ((<>) [])
let folder p l=函数
|当p(l)->(l::h)::t
|[]:u作为a->a
|_u作为->[]::a
设f-p-ls=
ls
|>List.rev
|>List.fold(fun a l->folder p l a)[[]]
|>List.filter(()[]))
至少文件夹是非常清晰有效的,但是你需要通过列表反转来为此付出代价。这是我的看法。你首先需要一些帮助功能:
// active pattern to choose between even and odd intengers
let (|Even|Odd|) x = if (x % 2) = 0 then Even x else Odd x
// fold function to generate a state tupple of current values and accumulated values
let folder (current, result) x =
match x, current with
| Even x, _ -> x::current, result // even members a added to current list
| Odd x, [] -> current, result // odd members are ignored when current is empty
| Odd x, _ -> [], current::result // odd members starts a new current
// test on data
[2; 4; 3; 7; 6; 10; 4; 5]
|> List.rev // reverse list since numbers are added to start of current
|> List.fold folder ([], []) // perform fold over list
|> function | [],x -> x | y,x -> y::x // check that current is List.empty, otherwise add to result
由于列表颠倒,我想转到#seq而不是list
这个版本在内部使用了变异(gasp!)来提高效率,但由于seq的开销,可能会稍微慢一点
let f p (ls) = seq {
let l = System.Collections.Generic.List<'a>()
for el in ls do
if p el then
l.Add el
else
if l.Count > 0 then yield l |> List.ofSeq
l.Clear()
if l.Count > 0 then yield l |> List.ofSeq
}
设f p(ls)=seq{
让l=System.Collections.Generic.ListHmm…坦率地说,它看起来并没有太好:Cons
模式可能会影响性能,最终筛选本质上是一样的。@svick——用C#实现一个命令式解决方案。上面的代码在功能上等同于最自然的C#解决方案。如果最后一组物品是匹配的。@Daniel对,你是。修复了它。这真的让它更难看了。:)这太糟糕了。尽管如此,这仍然是这里最简单的解决方案。您的编辑完全改变了问题。我建议您回滚编辑,选择原始问题的最佳答案,并将编辑作为一个单独的问题,如果您仍然需要社区反馈的话。@Daniel我觉得您在查看答案时是正确的。看到了吗ms everyone对我的问题的理解与我不同。当然,这是我的错,因为我没有首先强调可读性。谢谢你的建议。