Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/api/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Api Haskell中.NET中的GroupBy函数_Api_Haskell_Libraries - Fatal编程技术网

Api Haskell中.NET中的GroupBy函数

Api Haskell中.NET中的GroupBy函数,api,haskell,libraries,Api,Haskell,Libraries,NET框架中的LINQ库确实有一个非常有用的函数,名为,我一直在使用它。 它在Haskell中的类型看起来像 Ord b => (a-> b) -> [a] -> [(b, [a])] 其目的是根据给定的分类函数f将项目分类为多个存储桶,每个存储桶包含类似的项目,即(b,l),以便对于l中的任何项目x,fx==b 它在.NET中的性能是O(N),因为它使用哈希表,但在Haskell中,我对O(N*log(N))没有意见 我在标准Haskell库中找不到类似的东西。此外,

NET框架中的LINQ库确实有一个非常有用的函数,名为,我一直在使用它。 它在Haskell中的类型看起来像

Ord b => (a-> b) -> [a] -> [(b, [a])]
其目的是根据给定的分类函数
f
将项目分类为多个存储桶,每个存储桶包含类似的项目,即
(b,l)
,以便对于
l
中的任何项目
x
fx==b

它在.NET中的性能是O(N),因为它使用哈希表,但在Haskell中,我对O(N*log(N))没有意见

我在标准Haskell库中找不到类似的东西。此外,我在标准功能方面的实现有点笨重:

myGroupBy :: Ord k => (a -> k) -> [a] -> [(k, [a])]
myGroupBy f = map toFst
        . groupBy ((==) `on` fst) 
        . sortBy (comparing fst) 
        . map (\a -> (f a, a))
    where
        toFst l@((k,_):_) = (k, map snd l)
这绝对不是我想在我的问题代码中看到的东西

我的问题是:如何充分利用标准库来实现这个函数

此外,似乎没有这样一个标准函数,这意味着经验丰富的Haskeller可能很少需要它,因为他们可能知道一些更好的方法。这是真的吗?什么可以用来更好地实现类似的功能


另外,考虑到
groupBy
已经被采用,它的好名字是什么

使用
Data.Map
作为中间结构:

import Control.Arrow ((&&&))
import qualified Data.Map as M

myGroupBy f = M.toList . M.fromListWith (++) . map (f &&& return)
map
操作将输入列表转换为与包含元素的单例列表配对的键列表
M.fromListWith(++)
将其转换为
Data.Map
,当两个项具有相同的键时,将其连接起来,
M.toList
再次获取对


请注意,这会反转列表,因此如果需要,请对此进行调整。例如,如果您只需要每个组中元素的总和,也可以用其他类似幺半群的操作来替换
return
(++)

GHC.Exts.groupWith

groupWith :: Ord b => (a -> b) -> [a] -> [[a]]

作为广义列表理解的一部分引入:

这很有效!但是,有一点不同:它会反转生成的列表。顺便说一句,箭头的使用很好。它们甚至开始对我有意义了!啊,对。您可以通过使用
flip(+)
或仅使用
map(第二个反向)
进行后处理来解决此问题,另一个箭头示例:)后者可能更有效,因为您可以避免列表串联中可能出现的O(n^2)。@Rotsor:如果没有其他内容,则始终可以在事实之后反转结果列表。这也可能比您拥有的
Data.List
版本更快,因为
Data.Map
会按顺序排序,而
groupBy
只有一个相等谓词(想想它的含义……。
second
。。。我很高兴!我刚才写的代码包含
mapSnd f(a,b)=(a,fb)
<代码>翻转(++)——这是不可能的。O(N^2)不仅是可能的,而且似乎是这样保证的。@camccann,我认为groupBy的时间复杂度是线性的。我在这里错了吗?…另外,请注意,描述扩展的论文引用LINQ作为其背后的灵感,LINQ本身也受到Haskell的严重影响。它转啊转啊!美好的他们忘了返回
b
。)它在haskell中的类型是
ordb=>(a->b)->[a]->[(b[a])]
噢,我的。。。直到现在还没有人注意到!