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

时间:2018-06-11 03:59:05

标签: 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>,我该如何解决?

2 个答案:

答案 0 :(得分:3)

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

关于如何解决这个问题,没有足够的信息:我看到你想要获得数字而不是序列,但你不是说数字应该来自哪里,所以我无法帮助你。

答案 1 :(得分:3)

您已经在其他地方提到您是F#的初学者(八天前开始学习它),所以这里有一个快速指南,介绍如何阅读可能有助于您回答一些问题的F#文档这些问题你自己。让我们看一下documentation for the Seq module。它列出了许多可以在序列上调用的函数:appendaverageaverageByfiltermapgroupBy ..它们都有不同的类型签名,每个函数的类型签名都是它将要做什么的线索。让我们看一些例子:

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

首先,average,因为它最简单。类型符号中的->箭头告诉您这是一个函数。输入位于箭头左侧,输出位于箭头右侧。因此,类型签名意味着此函数采用seq<^T>并返回类型为^T的项。类型名称^前面的'T字符表示它是一种泛型类型,它将解析为运行代码时实际拥有的任何类型:int ,字符串,元组,等等。所以T只是你实际拥有的任何类型的占位符名称:如果你有整数,这是一个seq<int> -> int函数。如果你有字符串,这是一个seq<string> -> string函数,依此类推。 (类型前面的^字符表示它将在编译时解析,而前面的'字符表示它将在运行时解析。你赢了需要担心这种区别,直到你对F#有更多的经验,所以现在,只需将其中任何一个视为一个标志,这意味着&#34;这是一个通用类型&#34;)。因此average函数的类型签名告诉您它需要值序列并返回单个值

现在,averageBy。这更复杂。首先,这里有更多的箭头。这与一个名为currying的概念有关,这个概念在链接上得到了很好的解释,所以我不会深入研究它。在初学者级别,您应该将 final 箭头之后的任何内容视为函数的输出,并将所有其余类型作为函数的输入(将由箭头)。换句话说,像int -> char -> string这样的类型签名应该被理解为&#34;这是一个带有两个输入的函数,先是int,第二是char,然后返回{ {1}}&#34;

但是你看到string类型签名中('T -> ^U)位周围的括号吗?这些括号意味着他们在数学中的意思:单独阅读这部分内容。因此averageBy的第一个参数是类型averageBy('T -> ^U)的第二个参数的类型为averageBy,输出的类型为seq<'T>。现在,如果您查看类型签名^U,它中有一个箭头,因此它是一个函数。具体来说,它是一个采用泛型类型('T -> ^U)的函数并返回泛型类型T的函数。 (正如我之前所说,现在不要担心U'的区别。第二个参数是类型^的项序列,输出类型为T。该类型签名加上名称,为您提供了关于函数如何工作的线索:它将查看U类型的事物序列,并且对于每个类型,它将调用函数来转换T。 1}}成为T类型的东西。然后它返回一个U值作为输出:从名称中,您可以得出结论,它返回的单个值将是U函数生成的所有U值的平均值

所以类型签名'T -> ^U意味着第一个参数是一个带('T -> ^U) -> seq<'T> -> ^U并返回T的函数,第二个参数是{{1}类型的项目序列该函数返回一个U类型的单项。

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

因此,通过查看documentation,我们可以看到,如果您不希望序列作为输出,map是错误的调用。 U模块中有一个令人眼花缭乱的功能列表,所以您可能会感到有点不知所措。但是仔细查看类型签名,并了解每个签名的含义,对于确定哪个签名将根据您的数据执行您想要的操作有很大帮助。阅读https://fsharpforfunandprofit.com/posts/list-module-functions/也将对您有很大帮助:F#认真对待Seq.mapSeqList模块,因为非常相似,包括几乎所有相同的功能。因此,如果您知道Seq的作用,您也会知道ArrayList.averageBy的作用:唯一的区别在于它们作为输入采用何种类型的集合。因此即使该页面讨论了列表,它的建议也适用于Seq。

有人已在评论中回答了您的问题(只需执行Seq.averageBy,您应该得到您想要的结果),因此我不会在那里详细介绍。希望我花时间写这篇文章对你帮助你更深入地理解事情是有用的,这样你就可以在将来回答你自己的问题并且不必依赖于在Stack Overflow上提问。 (然后等待,有时是几个小时,以获得答案)。