请考虑以下地图:Map.fromList [(1,"foo"), (2,"bar"), (3,"foo")]
我想制作:Map.fromList [(1,"foo"), (2,"bar"), (3,"1")]
。先前与“foo”相关联的最后一个键3现在与“1”相关联 - 因此通过跟随该值(并将该字符串转换为数字),我仍然可以到达“foo”。如果结果是Map.fromList [(1,"3"), (2,"bar"), (3,"foo")]
,那也可以。
理想情况下,我会通过折叠原始地图来实现它。与此同时,我将逐步填充带有元素(“foo”,1),(“bar”,2)等的辅助(反向)地图。如果在辅助地图中找到当前关键字,而不是插入它进入最终的地图,我会插入它的相关值。
是否有一种简单/优雅的方式来排序,没有多次传递或Monad?
main = do
let names = Map.fromList [(1,"foo"), (2,"bar"), (3,"foo")]
link acc k v = -- insert into map1, depending map2's lookup
names' = Map.foldlWithKey link (Map.empty, Map.empty) names
putStrLn $ show names'
答案 0 :(得分:3)
我认为你能做的最好就是使用mapAccumWithKey
。然后,这样的事情:
deduplicate :: Map Int String -> Map Int String
deduplicate = snd . Map.mapAccumWithKey go Map.empty
where
go accum k v = case Map.lookup v accum of
Nothing -> (Map.insert v (show k) accum, v)
Just v' -> (accum, v')
这将逐个映射键,同时穿过Map String String
,跟踪已经看到的值及其对应的键。如果你想尝试一些平行的东西,显然有一些更酷的东西要做,但顺序这是最佳的 - 它应该是O(n log n)
,你至少需要检测共享密钥。
使用names' = deduplicate names
,我得到输出fromList [(1,"foo"),(2,"bar"),(3,"1")]
。