繁体   English   中英

为什么输出是 <seq> 而不是int in F#?

[英]Why output is <seq> and not int in F#?

这是我的代码:

 Csv.GetSample().Rows
 |> Seq.groupBy (fun row -> row.STATE,row.INCOME,row.CHILDREN)
 |> Seq.map (fun ((state,income,children),data) -> 
    let pctrepub = data|> Seq.map (fun row -> (100.0 - float row.otherparty)) 
    ((state,income,children),pctrepub))
 |> List.ofSeq

这是我理想的结果:

   (("TX", "51522", "0"), 65.0);
   (("AL", "6481", "1"), 51.4);
   (("MO", "78921", "1"), 25.1);
   (("TN", "12000", "4"), 62.1);
   (("PA", "79850", "2"), 41.2);
   (("NY", "79215", "1"), 31.0);
   (("CA", "79045", "2"), 50.5);

这就是我最终得到的结果:

   (("TX", "51522", "0"), <seq>);
   (("AL", "6481", "1"), <seq>);
   (("MO", "78921", "1"), <seq>);
   (("TN", "12000", "4"), <seq>);
   (("PA", "79850", "2"), <seq>);
   (("NY", "79215", "1"), <seq>);
   (("CA", "79045", "2"), <seq>);

为什么最后一行值显示为<seq> ,我该如何解决?

元组的最后一个元素是pctrepub ,这是Seq.map调用的结果,并且Seq.map返回一个序列,而不是数字。 因此,元组的最后一个元素是序列绝对不奇怪。

关于如何解决此问题,没有足够的信息:我看到您想获取数字而不是序列,但是您并不是在说数字应该从哪里来,所以我无法为您提供帮助。

您在其他地方提到过,您是F#的初学者(八天前开始学习它),因此,这是如何阅读F#文档的快速指南,它可以帮助您自己回答其中的一些问题。 让我们看一下Seq模块文档 它列出了许多可以在序列上调用的函数: appendaverageaverageByfiltermapgroupBy …它们都有不同的类型签名,每个函数的类型签名都是其作用的线索。 让我们看几个例子:

  • averageseq<^T> -> ^T返回序列中元素的平均值。
  • averageBy :( ('T -> ^U) -> seq<'T> -> ^U返回通过将函数应用于序列的每个元素而生成的结果的平均值。
  • map :( ('T -> 'U) -> seq<'T> -> seq<'U> -创建一个新集合,其元素是将给定功能应用于集合的每个元素的结果。

首先, average ,因为它是最简单的。 类型标记中的->箭头告诉您这是一个函数。 输入在箭头的左边,输出在箭头的右边。 因此,该类型签名意味着此函数采用seq<^T>并返回^T类型的项。 类型名称T前面的^'字符表示它是通用类型,它将在运行代码时解析为您实际拥有的任何类型:int,字符串,元组等。 因此, T只是您实际拥有的任何类型的占位符名称:如果您有int,则这是seq<int> -> int函数。 如果您有字符串,这是seq<string> -> string函数,依此类推。 (类型前面的^字符表示将在编译时进行解析,而类型前面的'字符表示将在运行时进行解析。在您完成此操作之前,无需担心这种区别。在F#方面有更多的经验,所以现在,只需将其中一个当作标志,就意味着“这是一个通用类型”)。 因此, average函数的类型签名告诉您,它采用一系列值并返回一个值

现在, averageBy 这更加复杂。 首先,这里还有更多箭头。 这与一个名为currying的概念有关,在链接上对此解释得很好,因此我不会深入探讨。 在初学者级别,您应该将最后一个箭头之后的内容视为函数的输出,并将所有其他类型视为函数的输入(将由箭头分隔)。 换句话说,类型签名(例如int -> char -> string应被理解为“这是一个需要两个输入的函数,首先输入int ,然后输入char ,然后返回string 。”

但是,您是否在averageBy类型签名中的('T -> ^U)位周围看到括号? 这些括号的含义与数学含义相同:请单独阅读本部分。 因此, averageBy的第一个参数是类型('T -> ^U) averageBy的第二个参数的类型为seq<'T> ,输出的类型为^U 现在,如果您查看类型签名('T -> ^U) ,它上面有一个箭头,因此它是一个函数。 具体来说,它是一个函数,它接受通用类型T的东西,并返回通用类型U的东西。 (正如我之前说的,现在不必担心' vs. ^区别)。 第二个参数是T类型的项目序列,输出是U类型。 该类型签名加上名称,为您提供有关函数工作方式的线索:它将查看类型T的事物序列,对于每个事物,它将调用该函数将T事物转换为事物。输入U 然后,它返回一个U值作为输出:从名称中可以得出结论,它返回的单个值将是'T -> ^U函数产生的所有U值的平均值。

因此,类型签名('T -> ^U) -> seq<'T> -> ^U表示第一个参数是一个接受T并返回U的函数,第二个参数是一个类型为null的项目序列T ,并且该函数返回单个类型U项目。

最后,让我们看一下map 它的类型签名看起来与averageBy非常相似:第一个参数还是一个接受T并将其转换为U的函数。 第二个参数还是T项的序列。 但是这次, map的结果将是一系列 U值,而不是单个值。

因此,通过查看文档 ,我们可以看到,如果您不希望将序列作为输出,则调用Seq.map是错误的事情。 Seq模块中的函数列表令人迷惑,因此您可能会觉得不知所措。 但是仔细查看类型签名,并理解每个签名的含义,对于确定哪个签名可以满足您的数据需求将大有帮助。 并且通读https://fsharpforfunandprofit.com/posts/list-module-functions/对您也有很大帮助:F#将ListSeqArray模块视为彼此极其相似 ,包括几乎所有相同的功能。 因此,如果您知道List.averageBy功能,那么您还将知道Seq.averageByArray.averageBy功能:唯一的区别在于它们将哪种类型的集合用作输入。 因此,即使该页面讨论列表,它的建议也适用于Seq。

有人已经在评论中回答了您的问题(只需执行Seq.map (fun row -> (row.STATE,row.INCOME,row.CHILDREN), 100.0 - float row.otherparty) ,您就应该得到想要的结果) ,因此我在这里不再赘述。 希望我花时间写这篇文章将对您有所帮助,以帮助您更深入地理解事物,以便您将来可以回答自己的问题,而不必太依赖于对Stack Overflow的询问(和然后等待,有时需要几个小时才能找到答案)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM