在F#中分块列表时我做错了什么

时间:2013-09-17 03:10:04

标签: f#

对我而言,F#并不容易。下面这段代码应该是一个列表。我不知道问题是什么。请帮忙。

let chunk items chunkSize =
    let folder = fun state x ->
        match state with (reversedResult, reversedChunk) ->
            if reversedChunk.Length < chunkSize then
                (reversedResult, x::reversedChunk)
            else
                ((reversedChunk |> List.rev)::reversedResult, [x])
    let alsmostDone = items |> List.fold folder ([], [])
    match alsmostDone with
    | (reversedResult, []) -> reversedResult |> List.rev
    | (reversedResult, lastReversedChunk) -> (lastReversedChunk |> List.rev)::reversedResult |> List.rev

enter image description here

5 个答案:

答案 0 :(得分:6)

我认为使用List.length更加“惯用”f#。然后你不需要任何类型的注释。所以:

...
if List.length reversedChunk < chunkSize then
...

答案 1 :(得分:4)

无法推断reversedChunk的类型,因此您需要指定类型。将第三行更改为:

match state with (reversedResult, reversedChunk : list<'T>) ->

答案 2 :(得分:3)

正如其他人已经提到的那样,您可以使用List.length代替Length来完成这项工作。实际上,将当前块长度保持为状态的一部分可能更好,因为List.length需要遍历整个列表来计算其长度 - 因此每次都会继续迭代块。

以下内容与原始代码几乎相同,但我将folder转换为普通函数(此处不需要lambda)并删除了match(因为您可以在直接在函数声明中声明)。然后我将reversedChunkSize添加到州:

let chunk items chunkSize =
    let folder (reversedResult, reversedChunk, reversedChunkSize) x =
      if reversedChunkSize < chunkSize then
          (reversedResult, x::reversedChunk, reversedChunkSize + 1)
      else
          ((reversedChunk |> List.rev)::reversedResult, [x], 1)
    let alsmostDone = items |> List.fold folder ([], [], 0)
    match alsmostDone with
    | (reversedResult, [], _) -> 
         reversedResult |> List.rev
    | (reversedResult, lastReversedChunk, _) -> 
         (lastReversedChunk |> List.rev)::reversedResult |> List.rev

答案 3 :(得分:1)

这比解决特定编码问题更能解决问题的第一句话。

随着(重新)从头开始发明自己的算法FP语言掌握也通过在标准核心库函数和组合器方面开发解决方案的惯用思想来促进。您正在解决的任务可以通过几个简单的惯用数据转换来实现:

let chunk size items =                     // test upon chunk 3 [1..6]
    items                                  // [1;2;3;4;5;6]
    |> List.mapi (fun i x -> (i/size,x))   // [(0, 1); (0, 2); (0, 3); (1, 4); (1, 5); (1, 6)]
    |> Seq.groupBy fst                     // seq [(0, seq [(0, 1); (0, 2); (0, 3)]); (1, seq [(1, 4); (1, 5); (1, 6)])]
    |> Seq.map snd                         // seq [seq [(0, 1); (0, 2); (0, 3)]; seq [(1, 4); (1, 5); (1, 6)]]
    |> Seq.map (Seq.map snd >> Seq.toList) // seq [[1; 2; 3]; [4; 5; 6]]
    |> Seq.toList                          // [[1; 2; 3]; [4; 5; 6]]

答案 4 :(得分:1)

'GetSlice'版本:

let chunk2 size items =
    [
        let arrs = items |> Seq.toArray
        let len = List.length items
        for i in [0..size..len-1] do
            let min = System.Math.Min(i+size, len)
            yield arrs.[i..min-1] |> Array.toList
    ]

let a = chunk2 6 [1..10000]