如何解决mapMaybe用于Data.Map中的键
我想将以下功能映射到Map
的键上
f :: a -> Maybe b
并丢弃Nothing
键,并保留Just
键,但从Just
中提取。就像Map.mapMaybe
,但要输入密钥
mapMaybeKeys :: (a -> Maybe b) -> Map a c -> Map b c
我在Hoogle中搜索了这种类型的签名,但没有找到任何内容。
我可以这样做:
mapMaybeKeys f
= Map.toList
. catMaybes
. fmap (fmap swap . traverse f . swap)
. Map.toList
或:
mapMaybeKeys f
= Map.mapKeys fromJust
. Map.delete Nothing
. Map.mapKeys f
还有更优雅的方式吗?
解决方法
具有列表理解力
import Data.Map (Map)
import qualified Data.Map as M
import Control.Arrow (first)
mapMaybeKeys :: Ord b => (a -> Maybe b) -> Map a c -> Map b c
mapMaybeKeys f m =
M.fromList [ (b,a) | (Just b,a) <- map (first f) . M.toList $ m ]
,
使用foldMapWithKey
(或foldrWithKey
)也很不错,而无需浏览中间列表。
mapMaybeKeys :: (Ord b) => (a -> Maybe b) -> Map a c -> Map b c
mapMaybeKeys f = Map.foldMapWithKey
(\ k a -> foldMap (\ k' -> M.singleton k' a) (f k))
-- or:
mapMaybeKeys f = Map.foldMapWithKey (flip (foldMap . flip M.singleton) . f)
-- or:
mapMaybeKeys = M.foldMapWithKey . fmap (flip (foldMap . flip M.singleton))
如果键函数返回foldMap
,则内部Nothing
会生成一个空映射。您可以添加一些帮助程序定义,以通过避免使用flip
来使它看起来更简单。请注意,您需要Ord
约束才能使用b
作为结果映射的键。
谢谢@Will Ness和@Jon Purdy,我喜欢您的解决方案,但经过一些调整,我认为我最喜欢我的原始解决方案:
import Data.Bitraversable (bitraverse)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (catMaybes)
mapMaybeKeys :: (Ord b) => (a -> Maybe b) -> Map a c -> Map b c
mapMaybeKeys f
= Map.fromList
. catMaybes
. fmap (bitraverse f Just)
. Map.toList
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。