Scala有一个功能groupBy
上列出了接受从列表项中提取密钥的功能,并返回另一个列表,其中的项目包括关键和生产是关键的项目列表的元组。 换句话说,这样的事情:
List(1,2,3,4,5,6,7,8,9).groupBy(_ % 2)
// List((0, List(2,4,6,8)), (1, List(1,3,5,7,9)))
(事实上,它看起来像在当前版本中,它提供了一个Map
,而不是,但是这并不重要)。 C#有一个更加有用的版本,可以让你的价值观,同时映射(如果说是非常有用的,你的关键功能只提取元组的一部分)。
Haskell有一个groupBy
,但它有点不同-这组根据一些比较函数的东西运行。
我去写它之前,有没有Scala的的等效groupBy
在Haskell? Hoogle没有什么我期望的签名看起来像(下)什么,但我可能刚刚听错了。
Eq b => (a -> b) -> [a] -> [(b,[a])]
你可以比较容易地编写自己的功能,但你需要放置Ord
或Hashable
,如果你想要一个有效的解决方案的约束对分类函数的结果。 例:
import Control.Arrow ((&&&))
import Data.List
import Data.Function
myGroupBy :: (Ord b) => (a -> b) -> [a] -> [(b, [a])]
myGroupBy f = map (f . head &&& id)
. groupBy ((==) `on` f)
. sortBy (compare `on` f)
> myGroupBy (`mod` 2) [1..9]
[(0,[2,4,6,8]),(1,[1,3,5,7,9])]
你也可以使用一个哈希表像Data.HashMap.Strict
,而不是为预期的线性时间排序。
具体来说,有以下应该工作:
scalaGroupBy f = groupBy ((==) `on` f) . sortBy (comparing f)
模,这并不让你的结果f
每个组中,但如果你真的需要它,你可以随时后期处理与
map (\xs -> (f (head xs), xs)) . scalaGroupBy f
这是不是在列表库中的函数。
你可以把它写成sortBy和GROUPBY的组成。
把一个trace
在f
表明,与@Niklas溶液, f
评估3次,长度为2或更多的任何列表上的每个元件。 我把以便修改它的自由f
被施加到每个元件仅一次。 目前尚不清楚创建和销毁元组的成本。但是是否小于评估的成本f
多次(因为f
可任意)。
import Control.Arrow ((&&&))
import Data.List
import Data.Function
myGroupBy' :: (Ord b) => (a -> b) -> [a] -> [(b, [a])]
myGroupBy' f = map (fst . head &&& map snd)
. groupBy ((==) `on` fst)
. sortBy (compare `on` fst)
. map (f &&& id)
该解决方案将打破和组由(FX),不管阉是排序或不
f = (`mod` (2::Int))
list = [1,3,4,6,8,9] :: [Int]
myGroupBy :: Eq t => (b -> t) -> [b] -> [(t, [b])]
myGroupBy f (z:zs) = reverse $ foldl (g f) [(f z,[z])] zs
where
-- folding function
g f ((tx, xs):previous) y = if (tx == ty)
then (tx, y:xs):previous
else (ty, [y]):(tx, reverse xs):previous
where ty = f y
main = print $ myGroupBy f list
结果:[(1,[1,3]),(0,[4,6,8]),(1,[9])]