F# Split list into sublists based on comparison of adjacent elements

后端 未结 6 801
日久生厌
日久生厌 2020-12-03 17:46

I\'ve found this question on hubFS, but that handles a splitting criteria based on individual elements. I\'d like to split based on a comparison of adjacent elements, so the

6条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-03 18:42

    Having thought about this a bit further, I've come up with this solution. I'm not sure that it's very readable (except for me who wrote it).

    UPDATE Building on the better matching example in Tomas's answer, here's an improved version which removes the 'code smell' (see edits for previous version), and is slightly more readable (says me).

    It still breaks on this (splitOn (<>) []), because of the dreaded value restriction error, but I think that might be inevitable.

    (EDIT: Corrected bug spotted by Johan Kullbom, now works correctly for [1;1;2;3]. The problem was eating two elements directly in the first match, this meant I missed a comparison/check.)

    //Function for splitting list into list of lists based on comparison of adjacent elements
    let splitOn test lst = 
        let rec loop lst inner outer = //inner=current sublist, outer=list of sublists
            match lst with 
            | x::y::ys when test x y -> loop (y::ys) [] (List.rev (x::inner) :: outer)
            | x::xs ->                  loop xs (x::inner) outer
            | _ ->                      List.rev ((List.rev inner) :: outer)
        loop lst [] []
    
    splitOn (fun a b -> b - a > 1) [1]
    > val it : [[1]]
    
    splitOn (fun a b -> b - a > 1) [1;3]
    > val it : [[1]; [3]]
    
    splitOn (fun a b -> b - a > 1) [1;2;3;4;6;7;8;9;11;12;13;14;15;16;18;19;21]
    > val it : [[1; 2; 3; 4]; [6; 7; 8; 9]; [11; 12; 13; 14; 15; 16]; [18; 19]; [21]]
    

    Any thoughts on this, or the partial solution in my question?

提交回复
热议问题