【问题标题】:F# casting type from query expression来自查询表达式的 F# 强制转换类型
【发布时间】:2015-03-10 02:47:13
【问题描述】:

我有一个如下形式的查询表达式:

let result = query { for row in context.Table do
                     where (row.id = 111111)
                     select (row.col1,row.col2,row.col3) }

Result 返回 IQueryable*Nullable*Nullable> 类型的值。我希望它返回 seq*seq*seq.

我可以尝试像这样改变它:

let result :seq<float>*seq<float>*seq<float> = query { for row in context.Table do
                                               where (row.id = 111111)
                                               select (row.col1,row.col2,row.col3) }
                     |> Seq.cast

但我明白了:

类型不匹配。期望 IQueryable * Nullable * Nullable> -> seq * seq * seq 但给定一个 IQueryable * Nullable * Nullable> -> seq
类型 'seq * seq * seq' 与类型 'seq'

不匹配

我做错了什么?

编辑:这就是我想要做的,听起来我的问题可能会给我一个有用的答案,但不是做我想做的最好的方法。这段代码很难看,但有效:

let col1 : seq<float> = query { for row in context.Table do
                                 where (row.id = 111111)
                                 select row.col1 }
                         |> Seq.cast 

let col2 : seq<float> = query { for row in context.Table do
                                 where (row.id = 111111)
                                 select row.col2 }
                         |> Seq.cast

let model = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(col1,col2)

如果我不强制转换为浮动,InterpolateAkima 将无法工作,因为它不接受 Nullable 类型。不过,我不想自己对每一列进行查询。我的最终目标是有一个函数,我可以传入 row.id 的任何值并获取 col1,col2 然后 col1,col3 等的模型。

【问题讨论】:

  • 你为什么要seq&lt;float&gt;*seq&lt;float&gt;*seq&lt;float&gt;?你期望它是什么?
  • @MarkSeemann,我将表中的值传递给不接受可为空值的函数。如果我一次拉一列,我可以使用 |> Seq.cast 转换为浮点数。我希望能够一次拉出所有列。

标签: f#


【解决方案1】:

这个问题分为两部分:

  • seq&lt;a * b * c&gt; 转换为seq&lt;a&gt; * seq&lt;b&gt; * seq&lt;c&gt;List.unzip3Array.unzip3 正是这样做的。

  • 摆脱 Nullable:这取决于您希望在值为 null 时发生什么。

    • 如果你想为空值返回 0:

      let col1, col2, col3 =
          query { for row in context.Table do
                  where (row.id = 111111)
                  let col1 = if row.col1.HasValue then row.col1.Value else 0.
                  let col2 = if row.col2.HasValue then row.col2.Value else 0.
                  let col3 = if row.col3.HasValue then row.col3.Value else 0.
                  select (col1, col2, col3) }
          |> Array.ofSeq
          |> Array.unzip3
      
    • 如果你想忽略有空的行:

      let col1, col2, col3 =
          query { for row in context.Table do
                  where (row.id = 111111 && row.col1.HasValue && row.col2.HasValue && row.col3.HasValue)
                  select (row.col1.Value, row.col2.Value, row.col3.Value) }
          |> Array.ofSeq
          |> Array.unzip3
      

【讨论】:

  • 谢谢,这行得通。有没有办法将其扩展到三列以上? Array.unzip3 只需要三个输入,我找不到更高的解压缩。
  • 确实没有用于解压缩大于 3 的元组的内置函数,但您始终可以自己实现;代码看起来像@Nikon the Third 的 seqTuple
【解决方案2】:

我和 Mark 一样想知道你想用这个来完成什么,但是,这里有一种方法可以做到:

open System
open System.Linq

// Helpers to recreate your circumstances.
type Context = { id : Int32; col1 : Nullable<Double>; col2 : Nullable<Double>; col3 : Nullable<Double>}
let context = Unchecked.defaultof<IQueryable<Context>>


let result = query { for row in context do
                     where (row.id = 111111)
                     select (row.col1,row.col2,row.col3) }


let seqTuple =
    result
    |> Seq.fold (fun (col1s, col2s, col3s) (col1, col2, col3) ->
        (if col1.HasValue then col1.Value :: col1s else col1s),
        (if col2.HasValue then col2.Value :: col2s else col2s),
        (if col3.HasValue then col3.Value :: col3s else col3s)
    ) ([], [], [])
    |> fun (col1s, col2s, col3s) ->
        List.rev col1s,
        List.rev col2s,
        List.rev col3s

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多