Operations on sublists

时间秒杀一切 提交于 2020-01-14 15:55:14

问题


I am currently wondering on an approach to split a list in sub-lists according to a given criteria. Because of the didactic purpose of this work, I do not use built-in functions. IE, the following program should, given a list, return a list of lists, where each sub-list does not have duplicates and is in ascending order:

increment [4;4;10;20;5;30;6;10] = [[4;10;20];[5;30];[6;10]]
increment [5;6;4;3;2;1] = [[5;6];[4];[3];[2];[1]]

My best attempt so far is based on this chunk of code I produced:

let rec increment li [lo] = 
    match li with
        |[]         ->  [lo]
        |[x]        ->  [x]::[lo]
        |x::y::xs   ->  if x = y then
                            increment (y::xs) [lo]
                        elif x < y then
                            x::(increment (y::xs) [lo])
                        else
                            (x::(increment xs [lo]))::[lo]

Unfortunately, I fail in creating the list of lists. The principle is correct. It is based on the function I built, that correctly isolates an ascending list if present:

let rec incrementAux li = 
    match li with
        |[]         ->  []
        |[x]        ->  [x]
        |x::y::xs   ->  if x = y then
                            incrementAux (y::xs)
                        elif x < y then
                            x::(incrementAux (y::xs))
                        else
                            x::(incrementAux [])

Any suggestion would be highly appreciated!


回答1:


If you want to do this without using the built-in functions on the List module (purely as a learning exercise), then you just need to understand map and fold so you can implement them yourself. I would start with this wikipedia article. Conveniently, you can easily implement rev in terms of fold, so that shouldn't be a problem. Once you understand what each function does, you can implement them yourself like so:

let rec fold f state = function
| [] -> state
| head::tail -> fold f (f state head) tail

let map f list =
    [for item in list -> f item]

let rev list = 
    fold (fun acc cur -> cur::acc) [] list

Then, you can just substitute your own functions for the built-in functions in Szer's solution:

let input = [4;4;10;20;5;30;6;10]
let output = [[4;10;20];[5;30];[6;10]]

let increment = 
    fold (fun (last::rest as total) x ->
        match last with
        | [] -> [x] :: rest
        | h::_ as last ->
        if x > h then (x::last)::rest
        else if x = h then total
        else [x]::total) [[]]
    >> map rev
    >> rev

let testOutput = increment input
testOutput = output

Note, this implementation of fold is different from how F# List does it. This is based on the simple Haskell example in the wikipedia article. The functionality is the same, but the implementation is quite different, as F# actually uses a mutable accumulator and a for-loop.




回答2:


You could do it without recursion. List.fold with a little bit of memory could help:

let input = [4;4;10;20;5;30;6;10]
let output = [[4;10;20];[5;30];[6;10]]

let increment = 
    List.fold (fun (last::rest as total) x ->
        match last with
        | [] -> [x] :: rest
        | h::_ as last ->
        if x > h then (x::last)::rest
        else if x = h then total
        else [x]::total) [[]]
    >> List.map List.rev
    >> List.rev

let testOutput = increment input
testOutput = output // true


来源:https://stackoverflow.com/questions/50405408/operations-on-sublists

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!