如何基于元组的第一个值生成笛卡尔联接?

时间:2019-04-22 00:30:01

标签: haskell

我有一个类型为(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

有任何提示吗?

1 个答案:

答案 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 fstcompare `on` fst相同;不幸的是,没有”还没有标准库中的类似equatingsequenceAsequenceonly 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后跟concatconcatMap(或(=<<),但这在这里有点太神秘了):

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个元组组中删除只有一个元组的那些元组。