基于密钥的功能折叠

时间:2015-04-20 08:38:22

标签: f# mapreduce functional-programming

我有一个map reduce代码,我通过某个键将每个线程分组,然后在reduce部分合并结果。我当前的方法是在累加器中搜索特定的键索引,然后mapi只检索此键的组合结果,其余部分保持不变:

let rec groupFolder sequence acc =
    match sequence with
        | (by:string, what) :: rest ->
            let index = acc |> Seq.tryFindIndex( fun (byInAcc, _) -> byInAcc.Equals(by) )
            match index with
                | Some (idx) -> 
                                acc |> Seq.mapi( fun i (byInAcc, whatInAcc) ->  if i = idx then (by, (what |> Array.append whatInAcc) ) else byInAcc, whatInAcc ) 
                                    |> groupFolder rest

                | None -> acc |> Seq.append( seq{ yield (by, what) } )
                              |> groupFolder rest

我的问题是,这是一种更实用的方法吗?

作为此减速器的示例输入

let GroupsCommingFromMap = [| seq { yield! [|("key1", [|1;2;3|] ); ("key2", [|1;2;3|] ); ("key3", [|1;2;3|]) |] }, seq { yield! [|("key1", [|4;5;6|] ); ("key2", [|4;5;6|] ); ("key3", [|4;5;6|]) |] }  |];;

GroupsCommingFromMap |> Seq.reduce( fun acc i -> 
                                    acc |> groupFolder (i |> Seq.toList))

预期结果应包含所有key1..key3,每个都包含数组1..6

1 个答案:

答案 0 :(得分:2)

根据您发布的代码,您不太清楚自己要做什么。你能包含一些样本输入(以及你想要的输出)吗?你的代码实际上是否适用于任何输入(它具有不完整的模式匹配,所以我怀疑......)

无论如何,您可以使用Seq.groupBy实现基于密钥的地图缩减。例如:

let mapReduce mapper reducer input = 
  input 
  |> Seq.map mapper
  |> Seq.groupBy fst
  |> Seq.map (fun (k, vs) -> 
      k, vs |> Seq.map snd |> Seq.reduce reducer)

下面:

  • mapper从输入序列中获取一个值并将其转换为键值对。然后mapReduce函数使用键
  • 对值进行分组
  • 然后reducer用于减少与每个键相关联的所有值

这可以让你创建一个像这样的字数统计函数(使用简单的映射器,将单词作为键返回,1为值,reducer只添加所有数字):

"hello world hello people hello world".Split(' ')
|> mapReduce (fun w -> w, 1) (+)

编辑:您提到的示例并没有" mapper"部分,但它有数组数组作为输入 - 所以也许更容易直接使用Seq.groupBy这样写:

let GroupsCommingFromMap = 
  [| [|("key1", [|1;2;3|] ); ("key2", [|1;2;3|] ); ("key3", [|1;2;3|]) |] 
     [|("key1", [|4;5;6|] ); ("key2", [|4;5;6|] ); ("key3", [|4;5;6|]) |]  |]

GroupsCommingFromMap
|> Seq.concat
|> Seq.groupBy fst
|> Seq.map (fun (k, vs) -> k, vs |> Seq.map snd |> Array.concat)