[英]Grouping data types by constructor in Haskell
給定此數據類型
data Val = X Int | Y Bool | Z Double deriving (Eq, Show)
以及諸如的列表
let vals = [X 1, Z 2.7, Y True, X 2, Z 3.14, Y True]
如何將vals
元素分組到這個列表中,
[[X 1,X 2],[Y True,Y True],[Z 2.7, Z 3.14]]
要添加到@ RamonSnir的答案,還可以使用“Scrap the boilerplate”框架自動構建用於按構造函數對數據類型進行分組的函數:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Function (on)
import Data.List (groupBy, sort)
data Val = X Int | Y Bool | Z Double
deriving (Eq, Ord, Show, Typeable, Data)
vals :: [Val]
vals = [X 1, Z 2.7, Y True, X 2, Z 3.14, Y True]
main :: IO ()
main = print $ groupBy (on (==) toConstr) $ sort vals
兩個重要部分是:
我有以下幾點:
data Val = X Int | Y Bool | Z Double deriving (Eq, Ord, Show)
vals :: [Val]
vals = [X 1, Z 2.7, Y True, X 2, Z 3.14, Y True]
valCtorEq :: Val -> Val -> Bool
valCtorEq (X _) (X _) = True
valCtorEq (Y _) (Y _) = True
valCtorEq (Z _) (Z _) = True
valCtorEq _ _ = False
然后:
*Main Data.List> groupBy valCtorEq $ sort vals
[[X 1,X 2],[Y True,Y True],[Z 2.7,Z 3.14]]
(這可能是極端矯枉過正,但修補它是一個有趣的問題!)
提供的答案有3個小問題:
Ord
(例如,某處有某個函數)會怎么樣? [X 2, X 1]
的結果應該是[X 1, X 2]
(如果您使用的話,那就是你得到的結果)基於sort
的解決方案)或元素應保持原始順序? 所以這是我能提出的最通用的解決方案。 它是穩定的,它不需要Ord
(事實上你甚至不需要觸摸原始數據類型)並且它運行在大約O(n * min(n,W))時間,其中W是機器的字大小(在我的身上,它是64)。 也就是說,一旦列表比64-ish元素更長,它就是線性的(我說'約',因為分組的元素仍然需要從差異列表重構)。
{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
import Data.Data
import qualified Data.IntMap as IM
groupByConstructor :: Data a => [a] -> [[a]]
groupByConstructor = map ($ []) . IM.elems . IM.fromListWith (flip (.))
. map (\a -> (constrIndexOf a, (a:))) where constrIndexOf = constrIndex . toConstr
-- definition of Val as originally posed, without Ord:
data Val = X Int | Y Bool | Z Double deriving (Eq, Show)
deriving instance Typeable Val
deriving instance Data Val
-- new example:
vals = [X 2, Z 2.7, Y True, X 1, Z 3.14, Y False, Z 0.2]
現在groupByConstructor vals
給出了[[X 2, X 1],[Y True, Y False],[Z 2.7, Z 3.14, Z 0.2]]
,我認為應該如此。
它不適用於對Int
s, Char
s, Float
或不可表示類型(如Ptr
和Array
列表進行排序。 通過使用一種算法可以使效率更高一些,該算法使用可能的構造函數來進一步推動線性常量,但IntMap
現在必須這樣做:-)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.