F#:类似Clojure中的配分函数
Clojure有一个很好的函数叫做partition,它可以处理序列。它将一个给定的序列分解为一个同样长的列表序列。第一个参数指定fragaments的长度。第二个参数是一个偏移量,用于指定片段的下一个起点F#:类似Clojure中的配分函数,clojure,f#,Clojure,F#,Clojure有一个很好的函数叫做partition,它可以处理序列。它将一个给定的序列分解为一个同样长的列表序列。第一个参数指定fragaments的长度。第二个参数是一个偏移量,用于指定片段的下一个起点 (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
(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))
我在寻找F#中的一个等价函数。显然,List.partition还做了其他事情()。也许有一个图书馆提供这样的功能 在F#中有两个类似的函数:windowed
,它类似于Clojure的分区,但第二个参数固定为1,第二个参数等于第一个参数
您可以将两者结合起来,获得所需的功能。下面是一个列表示例:
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)
你可以自己实现这个函数,正如@Gustavo所展示的,这并不难。一个问题是,您刚刚完成的功能是否正常工作 下面是一个用于测试配分函数属性的实现和属性测试
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
打开FsCheck
let分区(大小:int)(增量:int)(vs:'T[]):'T[]=
让大小=最大1个大小
设增量=最大1增量
让长度=vs.长度
[|对于[size..increment..length]中的i]->与[i-size..(i-1)]|]
let range(n:int):int[]=[|0..(n-1)|]
类型属性()=
静态成员``所有分区的大小``(大小:int,增量:int,vs:int[])=
(大小>1和增量>1和长度>1)=>
乐趣()->
let partitions=分区大小增量vs
//迭代分区并确保它们具有相同的长度=大小
let rec check=函数
|当我
partitions.Length->partitions[i].Length=size&&(检查(i+1))
|_uu->true
检查0
静态成员``所有分区都以正确的方式递增``(大小:int,递增:int,vs:int[])=
(大小>1和增量>1和长度>1)=>
乐趣()->
设ivs=vs |>Array.mapi(乐趣i v->(i,v))
let partitions=分区大小增量ivs
//迭代分区并确保第一个元素具有正确的增量
let rec check=函数
|当i
设ii,vv=分区[i].[0]
ii=(i*增量)和&vv=vs.[ii]&&(检查(i+1))
|_uu->true
检查0
静态成员``所有分区都有正确的内容``(大小:int,增量:int,vs:int[])=
(大小>1和增量>1和长度>1)=>
乐趣()->
设ivs=vs |>Array.mapi(乐趣i v->(i,v))
let partitions=分区大小增量ivs
//迭代分区并确保分区中的每个元素都是正确的元素
let rec check=函数
|当i
让partition=partitions[i]
设exp=i*增量
让rec检查分区=函数
|当i
设ii,vv=partition[i]
ii=(exp+i)和&vv=vs.[ii]&检查分区(i+1)
|_uu->true
检查分区0&(检查(i+1))
|_uu->true
检查0
[]
让主argv=
范围5 |>分区3 1 |>打印fn“%A”
范围20 |>分区4 6 |>打印fn“%A”
范围20 |>分区4 3 |>打印fn“%A”
让config={config.Quick with MaxFail=100000;MaxTest=1000}
//生成随机数据并确保属性适用于任何随机数据
检查所有配置
0
所以即使你没有要求这个,我想也许你对它感兴趣