2

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

在此处输入图像描述

4

5 回答 5

6

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

...
if List.length reversedChunk < chunkSize then
...
于 2013-09-17T07:20:23.807 回答
4

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

match state with (reversedResult, reversedChunk : list<'T>) ->
于 2013-09-17T04:57:36.650 回答
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
于 2013-09-17T14:54:39.190 回答
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]
于 2013-09-17T09:06:59.173 回答
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]]
于 2013-09-17T06:00:54.893 回答