【问题标题】:key based functional fold基于键的功能折叠
【发布时间】:2015-06-26 21:15:00
【问题描述】:

我有一个 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

我的问题是,这是实现这一目标的更实用的方法吗?

作为这个reducer的示例输入

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

【问题讨论】:

    标签: f# mapreduce functional-programming


    【解决方案1】:

    从您发布的代码来看,您想要做什么并不是很清楚。您能否包括一些示例输入(以及您想要获得的输出)?并且您的代码实际上是否适用于任何输入(它的模式匹配不完整,所以我怀疑...)

    无论如何,您可以使用Seq.groupBy 实现基于键的map reduce。例如:

    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) (+)
    

    编辑:您提到的示例实际上并没有“映射器”部分,而是将数组数组作为输入 - 所以使用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)
    

    【讨论】:

    • 感谢托马斯的回答。我添加了映射器的示例结果以及我的期望。所以 group by 就是答案。当然,然后我可以简单地追加第二个reduce。我在舌尖上。
    • @user3853059 又添加了一个示例来处理您描述的情况。
    • 哦,我忘了说映射器自己做了一个分组,它只是以我在示例中给你的格式返回组。再次感谢您的回答
    猜你喜欢
    • 2011-01-22
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 1970-01-01
    • 2015-01-07
    • 2012-08-31
    相关资源
    最近更新 更多