你如何使用Seq。按F#中的函数平均一行中的平均数据,按另一行中的数据分组?

时间:2018-06-06 22:42:49

标签: f#

我有两行,State和Income。有多个行具有相同的状态,但我希望每个状态有一行。因此,我希望按州平均所有收入数据,因此我可以得到每个州的平均值,每个州只能获得一个值/行。这是我尝试通过State行对Income行中的值进行平均。 我按顺序对序列进行了分组:

Seq.groupBy(fun row - > row.State)

但是,当我尝试对已经按州(从上面)分组的收入列中的数据进行平均时:

Seq.average(有趣的行 - > row.Income)

它给了我这个错误:

"错误FS0001:期望支持运营商的类型' +'但给定一个函数类型。您可能缺少函数的参数。"

我做错了什么?

1 个答案:

答案 0 :(得分:6)

如果您想传入某个功能,则需要Seq.averageBy,而不是Seq.averageSeq.average采用一系列数字,而Seq.averageBy采用函数和T类型的事物序列(该函数应该采用类型为T的函数并返回一个数字。)

此外,如果您首先使用Seq.groupBy,请注意它返回一系列元组,其中元组的第一个元素是键,第二个元素是一系列值那把钥匙。 (在类型签名中,这由类型seq<'Key * seq<'T>>表示)。所以你想要的有点复杂,我将引导你完成它:

  1. 首先,如果您想获得整个序列的平均值,那么它将是rows |> Seq.averageBy(fun row -> row.Income)
  2. 但首先,您正在调用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 })
    }
    
  3. 最后你想要的是:

    seq {
        (TX, 12345.0)
        (CA, 34567.0)
        (NY, 23456.0)
    }
    
  4. 因此,您想要的是以Seq.groupBy转换生成的序列,以保持键但转换值序列的方式。每当你想到&#34;我想保留这个序列但将其内容转换为其他内容&#34;时,你需要Seq.map

  5. Seq.map接受一个函数,它接受一个T类型的项目(无论T可能是什么),但我们可以使用destructuring in function parameters(在该页面上查找addOneToTuple示例)让它变得更简单:因为我们知道&#34;外部&#34;我们映射的序列是(key, values)的元组,我们可以编写函数来获取(key, values)元组:fun (key, values) -> key, (values |> Seq.averageBy ...)就是你想要的。
  6. 因此,您要使用的管道,首先分组然后平均每个组中的值(同时保持组密钥)将如下所示:

    rows
    |> Seq.groupBy (fun row -> row.State)
    |> Seq.map (fun (state, groupedRows) ->
        let averageIncome = groupedRows |> Seq.averageBy (fun row -> row.Income)
        (state, averageIncome))
    
  7. 那应该这样做。请注意,在最后的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.mapSeq.averageBy合并在一起。