我有一个类型为(Int,String)
的元组列表,并且我想生成一个类型为[String]
的列表,其中每个字符串都是具有相同{的元组的第二个元素的笛卡尔连接排列{1}}值。例如:
输入:Int
输出:[(1,"abc"),(1,"def"),(2,"ghi"),(2,"kl")]
我尝试了这种方法,但是我找不到只用相同的["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf", "gk", "gl", "hk", "hl", "ik", "il"]
值来替换元组的方法:
Int
有任何提示吗?
答案 0 :(得分:1)
您可以使用groupBy
将元组分开:
import Data.Function (on)
import Data.Ord (comparing)
import Data.List
possible_keys :: Ord k => [(k, [c])] -> [[c]]
possible_keys = concat . fmap sequenceA . fmap (fmap snd)
. groupBy ((==) `on` fst) . sortBy (comparing fst)
(我假设输入列表不一定要排序。我只是通过键进行排序,以使其具有最小的侵入性。comparing fst
与compare `on` fst
相同;不幸的是,没有”还没有标准库中的类似equating
。sequenceA
与sequence
,only more general相同。)
可以稍微减少一点。第二函子定律允许我们结合fmap
的连续使用:
possible_keys :: Ord k => [(k, [c])] -> [[c]]
possible_keys = concat . fmap (sequenceA . fmap snd)
. groupBy ((==) `on` fst) . sortBy (comparing fst)
fmap
后跟sequenceA
的是traverse
:
possible_keys :: Ord k => [(k, [c])] -> [[c]]
possible_keys = concat . fmap (traverse snd)
. groupBy ((==) `on` fst) . sortBy (comparing fst)
最后,列表上的fmap
后跟concat
是concatMap
(或(=<<)
,但这在这里有点太神秘了):
possible_keys :: Ord k => [(k, [c])] -> [[c]]
possible_keys = concatMap (traverse snd)
. groupBy ((==) `on` fst) . sortBy (comparing fst)
请注意,这将为只有一个元组的键生成长度为一的字符串-sequenceA ["abc"]
为["a","b","c"]
。如果您不希望这样做,可以在filter
之后groupBy
个元组组中删除只有一个元组的那些元组。