【问题标题】:f# how to filter mixed data type for a specific typef# 如何过滤特定类型的混合数据类型
【发布时间】:2014-11-21 18:33:26
【问题描述】:

我正在尝试过滤特定类型的混合数据类型,比如浮点数(理想情况下这是动态的)

这是我的例子:

let testobj = [8.0 , 1.0, "bla" ; 8.0 , 1.0, "bla"]

let testfun data = data |> List.filter (fun a -> 
      match a.GetType() with 
      | float -> a
      | _ -> 0.0)

现在这应该返回 [8.0 , 1.0, 0.0 ; 8.0 , 1.0, 0.0] for testobj 但我得到一个错误,该函数的类型为 bool

【问题讨论】:

  • testobj 的类型为 (float * float * string) list。这是您需要的,还是应该是任何类型的对象列表 (obj list)?
  • 它实际上是对象[,],我想要除了第一行和前两列之外的所有双打

标签: f#


【解决方案1】:

这不是你想做的。

说真的。

F# 希望列表是同质的,而您的列表不是同质的。 floatstring 不共享一个公共基类,因此您不会从中获取列表。

F# 想要你做的是为此使用一个有区别的联合。所以如果你有这种类型:

type Composite =
    | Num of float
    | Str of string

你可以这样定义你的列表:

let data = [ Num(8.0); Num(1.0); Str("bla"); Num(8.0); Num(1.0); Str("bla") ]

从那里您可以对类型进行模式匹配,您的函数如下所示:

let testfun d = d |> List.map (fun a ->
    match a with
    | Num x -> a
    | _ -> Num(0.0) )

data|> testfun |> printfn "%A"

输出将是:

 [Num 8.0; Num 1.0; Num 0.0; Num 8.0 ; Num 1.0 ; Num 0.0;]

如果您最终想要浮动而不是合成,请执行以下操作:

let testfun1 d = d |> List.map (fun a ->
    match a with
    | Num x -> x
    | _ -> 0.0 )

它摆脱了复合类型。该代码中的所有内容(我的意思是所有内容)都是类型强且类型安全的。

从实际维护的角度来看,我会避开匹配中的 _ 情况,而是使用我所有的类型,理由是如果我扩展 Composite 以包含另一种类型,我会希望编译器对我大喊大叫并查看每个使用它的函数,而不是默默地假设 0.0 或 Num(0.0) 确实是我想要的。

例如,如果我向该类型添加整数,如果我想对复合​​列表的内容求和,这将完全错误。

鉴于您被困在/一心想要弱类型的数据集,那么您想要这样的东西:

let testfun2 d = d |> Array.map (fun (a:Object) ->
    match a with
    | :? float as x -> x
    | _ -> 0.0
    )

let data:Object[] = [|8.0; 1.0; "bla"; 8.0; 1.0; "bla"|]
data |> testfun2 |> printfn "%A"

它将打印您期望的内容。请注意,我使用的是正确的数组语法和 not 列表语法。

然而这对 F# 来说真的很不靠谱。看看我必须如何用类型装饰ad?在我之前的代码中,语言可以解决所有问题。如果我也不修饰,我会得到编译器错误,因为我们真的违背了类型系统的本质。

如果是你,我会倾向于先做这样的事情:

let recast d = d |> Array.map (fun (a:Object) ->
    match a with
    | :? float as x -> Num x
    | :? string as x -> Str x
    | _ -> raise (ArgumentException("that was unexpected: " + a.GetType().Name))
    )

把它变成一个复合数组,现在是强类型。如果你在Array.map 之后添加|> Array.toList,你会得到一个列表(如果你想要的话)。

【讨论】:

  • 谢谢。问题是我从数据库中获取了一个对象 [,],因为它包含 1 个标题行和两个字符串列以及其余的双精度数,我只想过滤双精度数。
  • 您在上面声明的是一个元组列表。你有一个对象数组吗?
  • yes object[9000,500],元组只是一个关于如何过滤的测试
猜你喜欢
  • 2020-09-17
  • 2017-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多