F#: 过滤掉"None"并仅保留"Some"

3

如何有效地对列表/序列进行分组/筛选的快速问题。

  1. 筛选仅包含非空可选字段的记录
  2. 删除"option"参数,以使将来的处理更容易(因为None已被筛除)
  3. 分组(我认为这没有问题)

我是否采用了最佳方法?

谢谢!

type tmp = {
    A : string
    B : int option }

type tmp2 = {
    A : string
    B : int }



let inline getOrElse (dft: 'a) (x: 'a option) =
    match x with
    | Some v -> v
    | _      -> dft

let getGrouped (l: tmp list) =
    l |> List.filter  (fun a -> a.B.IsSome)
      |> List.map  (fun a -> {A = a.A ; B = (getOrElse 0 (a.B)) })
      |> List.groupBy (fun a -> a.A)

1
你的getOrElse函数是标准Option.defaultValue函数的重新实现,但由于你的过滤器删除了B为None的列表项,所以你不需要它,因为B必须始终是Some int。 - Jackson
2个回答

7

当涉及到 option 时,最自然的处理 map+filter 的方法是使用 choose,它将这两个操作结合起来,并从过滤输出中删除选项包装器。

您的示例可能如下所示:

let getGrouped (l: tmp list) =
    l
    |> List.choose (fun a ->
       a.B 
       |> Option.map (fun b -> {A = a.A; B = b})
    |> List.groupBy (fun a -> a.A)

谢谢,我喜欢这种方法。至少这些函数在签名方面比Deedle的更清晰。 - Jeff_hk

2

简单的解决方案是使用选项可以被转换为具有一个或零个元素列表的属性,您可以定义以下功能:

最初的回答

def optionToList[A](opt: Option[A]): List[A] = opt.toList

let t1 ({A=a; B=b} : tmp) =
        match b with
        | (Some i) -> [{ A = a; B= i}] 
        | _ -> []

let getGrouped (l: tmp list) =
    l |> List.collect t1
      |> List.groupBy (fun a -> a.A)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接