按功能值分组到Multimap中

时间:2014-02-25 21:38:38

标签: haskell grouping multimap

假设我有一个像这样的值列表:

["abc","abd","aab","123"]

我希望通过使用将任何元素映射到键的函数将这些值分组到Haskell中的MultiMap(概念上,不限于特定的数据结构)。

对于此示例,我们将使用take 2作为映射器。

我打算得到的结果(概念上,作为JSON):

{"ab":["abc","abd"], "aa":["aab"], "12":["123"]}

在此示例中,我将使用[(String, [String])]作为Multimap数据结构。

我的基本想法(概念上):

let datalist = ["abc","abd","aab","123"]
let mapfn = take 2
let keys = nub $ map mapfn datalist
let valuesForKey key = filter ((==key).mapfn) datalist
let resultMultimap = zip keys $ map valuesForKey keys

我的问题:

  1. 有没有更好的方法(在基本或外部包中)这样做?我想避免使用自定义代码。
  2. 如果1)不适用,是否保证GHC会对此进行优化,以便对数据列表进行一次传递就足以生成完整的多重映射(而不是每个密钥运行一次filter)?
  3. 从概念上讲,这个问题类似于SQL GROUP BY语句。

2 个答案:

答案 0 :(得分:8)

使用fromListWith中的Data.Map

> let xs = ["abc","abd","aab","123"]
> let f = take 2
> Data.Map.fromListWith (++) [(f x, [x]) | x <- xs]
fromList [("12",["123"]),("aa",["aab"]),("ab",["abd","abc"])]

答案 1 :(得分:2)

编辑2014-03-28:我的功能现已发布在Hackage上,请参阅group-with

欢迎

Pull requests


基于hammar's excellent answer我将两个可重用的函数放在一起来解决这个问题。

groupWith完全解决了我的要求。 groupWithMulti通过允许标识符生成函数(例如我的示例中的take 2)为单个值返回多个标识符来概括该概念(在我的示例中,值为{{1}之一) }),或者根本没有。 该值将添加到["abc","abd","aab","123"]生成的任何标识符的Map值。

f

只需使用import Data.Map (Map) import qualified Data.Map as Map -- | Group values in a list by their identifier, being returned -- by a given function. The resulting map contains, -- for each generated identifier the values (from the original list) -- that yielded said identifier by using the function groupWith :: (Ord b) => (a -> b) -> [a] -> (Map b [a]) groupWith f xs = Map.fromListWith (++) [(f x, [x]) | x <- xs] -- | Like groupWith, but the identifier-generating function -- may generate multiple outputs (or even none). -- The corresponding value from the original list will be placed -- in the identifier-corresponding map entry for each generated -- identifier groupWithMulti :: (Ord b) => (a -> [b]) -> [a] -> (Map b [a]) groupWithMulti f xs = let identifiers x = [(val, [x]) | val <- f x] in Map.fromListWith (++) $ concat [identifiers x | x <- xs] 将这些函数的结果转换回元组列表。

当我有空闲时间时,我将尝试在内存数据分组中使用此方法在Hackage上创建一个通用库。