我正在尝试在包含许多字段的数据类型中返回具有特定Status
的键。我尝试了一些东西,但没有任何东西甚至编译!任何人都有我可以使用的小费吗?
data Configuration v = Configuration {
configurationMap :: Map.Map v Status,
configurationGraph :: Graph v
}
verticesByStatus :: Ord v => Status -> Configuration v -> [v]
verticesByStatus ???
答案 0 :(得分:1)
可能有一种更优雅的方式来表达这一点,但这是一个解决方案:
verticesByStatus status (Configuration map graph) = fst <$> (filter ((== status) . snd) $ M.assocs map)
那么这里发生了什么?首先,我们对配置参数进行模式匹配,以提取它的两个组件,并将它们分配给变量map
和graph
。现在让我们打破右手边:
fst <$> (filter ((== status) . snd) $ Map.assocs map)
^-- This comes from the Data.Map package and splits a map into a list of tuples of key/value pairs.
^-- Here, we filter our new list of key/values based on the values, and find only those that match the input status
^-- Last, we fmap the function fst over the whole list to extract only the keys that match your given status
表达此功能的另一种方法是通过eta-reduction来简化它。一种方法是使用configurationMap
函数来提取配置的那部分而不是模式匹配:
verticesByStatus status = fmap fst . filter ((== status) . snd) . Map.assocs . configurationMap
答案 1 :(得分:0)
Data.Map
中的地图有filter
,可以直接用于配置地图:
verticesByStatus :: Ord v => Status -> Configuration v -> [v]
verticesByStatus status = Map.keys . Map.filter (== status) . configurationMap
Map.keys
生成地图中的键列表。 (如果您想要一个值列表,可以使用Map.elems
或等同于toList
中的Data.Foldable
。请注意,有些令人困惑的是,后者与... {0}相同Map.toList
,它会生成一个键值对列表,就像jkeuhlen的答案中的Map.assocs
一样。)
答案 2 :(得分:0)
verticesByStatus :: Ord v => Status -> Configuration v -> [v]
verticesByStatus status (Configuration cMap cGraph) =
[ v
| v <- vertices cGraph,
Just(status) == (Map.lookup v cMap)]
一些注意事项:
我会选择避免Map.assocs
,因为它需要花费额外的O(n)才能运行,您可以获得配置图中的值,而无需先将其转换为元组列表(请参阅Map docs)。
我选择了列表理解,而不是将map
和filter
组合在一起,因为我发现它更容易阅读(我在阅读this article后选择的内容)
我们可以检查查找是否返回Just
或Nothing
,然后使用Just
在fromJust
的情况下提取值但是这将是更多的代码,可能更难阅读。它看起来像是:
verticesByStatus :: Ord v => Status -> Configuration v -> [v]
verticesByStatus status (Configuration cMap cGraph) =
[ v
| v <- vertices cGraph,
let vStatus = Map.lookup v cMap,
if (isJust vStatus) then (status == (fromJust vStatus)) else False]