F #: split function like in Clojure

Clojure has a nice feature called a section that works on sequences. It breaks the given sequence into a sequence of equally long lists. The first parameter indicates the length of the fragments. The second parameter is the offset, which determines the next run of the fragment.

(partition 3 1 (range 5))
;;=> ((0 1 2) (1 2 3) (2 3 4))

(partition 4 6 (range 20))
;;=> ((0 1 2 3) (6 7 8 9) (12 13 14 15))

(partition 4 3 (range 20))
;;=> ((0 1 2 3) (3 4 5 6) (6 7 8 9) (9 10 11 12) (12 13 14 15) (15 16 17 18))

https://clojuredocs.org/clojure.core/partition

I am looking for an equivalent function in F #. It is clear that List.partition is doing something else ( https://msdn.microsoft.com/en-us/library/ee353782.aspx ). Maybe there is a library that offers such a function?

+4
source share
2 answers

F # : windowed, Clojure, , 1 chunkBySize , .

. :

let partition x y = List.windowed x >> List.chunkBySize y >> List.map List.head

, , , . , , , :

let partition x y = Seq.windowed x >> Seq.chunkBySize y >> Seq.map (Seq.head >> seq)
+7

, @Gustavo, . , , , .

, , FsCheck hold.¨

FsCheck - , .

open FsCheck

let partition (size : int) (increment : int) (vs : 'T []) : 'T [] [] =
  let size      = max 1 size
  let increment = max 1 increment
  let length    = vs.Length
  [| for i in [size..increment..length] -> vs.[(i - size)..(i - 1)] |]

let range (n : int) : int [] = [| 0..(n - 1) |] 

type Properties() =

  static member ``all partitions have the right size`` (size : int, increment : int, vs : int []) =
    (size > 1 && increment > 1 && vs.Length > 1) ==> 
      fun () ->
        let partitions = partition size increment vs
        // Iterates over partitions and make sure they have the same Length = size
        let rec check = function
          | i when i < 
            partitions.Length -> partitions.[i].Length = size && (check (i + 1))
          | _ -> true
        check 0

  static member ``all partitions have been incremented the right way`` (size : int, increment : int, vs : int []) =
    (size > 1 && increment > 1 && vs.Length > 1) ==>
      fun () ->
        let ivs = vs |> Array.mapi (fun i v -> (i,v))
        let partitions = partition size increment ivs
        // Iterates over partitions and make sure the first element has the right increment
        let rec check = function
          | i when i < partitions.Length -> 
            let ii, vv = partitions.[i].[0]
            ii = (i*increment) && vv = vs.[ii]  && (check (i + 1))
          | _ -> true
        check 0

  static member ``all partitions have the right content`` (size : int, increment : int, vs : int []) =
    (size > 1 && increment > 1 && vs.Length > 1) ==> 
      fun () ->
        let ivs = vs |> Array.mapi (fun i v -> (i,v))
        let partitions = partition size increment ivs
        // Iterates over partitions and make sure the each in the partition is correct element
        let rec check = function
          | i when i < partitions.Length -> 
            let partition = partitions.[i]
            let exp       = i*increment
            let rec check_partition = function
              |  i when i < partition.Length -> 
                let ii, vv = partition.[i] 
                ii = (exp + i) && vv = vs.[ii] && check_partition (i + 1)
              | _ -> true
            check_partition 0 && (check (i + 1))
          | _ -> true
        check 0

[<EntryPoint>]
let main argv = 
  range 5   |> partition 3 1 |> printfn "%A"
  range 20  |> partition 4 6 |> printfn "%A"
  range 20  |> partition 4 3 |> printfn "%A"

  let config = { Config.Quick with MaxFail = 100000; MaxTest = 1000 }

  // Generates random data and make sure the properties holds for any random data
  Check.All<Properties> config

  0

, , , , , .

+2

Source: https://habr.com/ru/post/1627347/


All Articles