我有两行,State和Income。有多个行具有相同的状态,但我希望每个状态有一行。因此,我希望按州平均所有收入数据,因此我可以得到每个州的平均值,每个州只能获得一个值/行。这是我尝试通过State行对Income行中的值进行平均。 我按顺序对序列进行了分组:
Seq.groupBy(fun row - > row.State)
但是,当我尝试对已经按州(从上面)分组的收入列中的数据进行平均时:
Seq.average(有趣的行 - > row.Income)
它给了我这个错误:
"错误FS0001:期望支持运营商的类型' +'但给定一个函数类型。您可能缺少函数的参数。"
我做错了什么?
答案 0 :(得分:6)
如果您想传入某个功能,则需要Seq.averageBy
,而不是Seq.average
。 Seq.average
采用一系列数字,而Seq.averageBy
采用函数和T类型的事物序列(该函数应该采用类型为T的函数并返回一个数字。)
此外,如果您首先使用Seq.groupBy
,请注意它返回一系列元组,其中元组的第一个元素是键,第二个元素是一系列值那把钥匙。 (在类型签名中,这由类型seq<'Key * seq<'T>>
表示)。所以你想要的有点复杂,我将引导你完成它:
rows |> Seq.averageBy(fun row -> row.Income)
。但首先,您正在调用Seq.groupBy
,它会返回一系列元组。如果您执行了rows |> Seq.groupBy (fun row -> row.State) |> Seq.averageBy (fun row -> row.Income)
,那么您会收到错误消息,指出元组没有名为Income
的属性。因为Seq.groupBy
调用已将您的数据转换为以下内容:
seq {
(TX, seq { row1, row4, row7 })
(CA, seq { row2, row5, row8 })
(NY, seq { row3, row6, row9 })
}
最后你想要的是:
seq {
(TX, 12345.0)
(CA, 34567.0)
(NY, 23456.0)
}
因此,您想要的是以Seq.groupBy
和转换生成的序列,以保持键但转换值序列的方式。每当你想到&#34;我想保留这个序列但将其内容转换为其他内容&#34;时,你需要Seq.map
。
Seq.map
接受一个函数,它接受一个T类型的项目(无论T可能是什么),但我们可以使用destructuring in function parameters(在该页面上查找addOneToTuple
示例)让它变得更简单:因为我们知道&#34;外部&#34;我们映射的序列是(key, values)
的元组,我们可以编写函数来获取(key, values)
元组:fun (key, values) -> key, (values |> Seq.averageBy ...)
就是你想要的。因此,您要使用的管道,首先分组然后平均每个组中的值(同时保持组密钥)将如下所示:
rows
|> Seq.groupBy (fun row -> row.State)
|> Seq.map (fun (state, groupedRows) ->
let averageIncome = groupedRows |> Seq.averageBy (fun row -> row.Income)
(state, averageIncome))
那应该这样做。请注意,在最后的Seq.map
步骤中,我必须确保返回(state, averageIncome)
的元组;如果我刚刚返回groupedRows |> Seq.averageBy (fun row -> row.Income)
的结果,那么我会将一个元组映射到单个值,并且你将得到一个不再有状态的平均收入序列。
我希望这可以帮助您了解如何在F#中解决像这样的问题。有lots of different functions that work on collections like lists or sequences,起初可能有点令人困惑。但无论您是初学者还是经验丰富的F#开发人员,基本方法都是一样的:您首先要说的是&#34;我有什么样的数据,以及当我完成时我想要的数据类型?&#34;然后你寻找一个具有正确&#34;形状的功能&#34;将A类数据转换为B类数据;如果没有单一的功能,你可以将几个功能(如构建块)放在一起,以获得所需的整体功能。 (例如,我们如何将Seq.map
和Seq.averageBy
合并在一起。