【问题标题】:How to generate the cartesian join of a list of tuples based on their first value? [duplicate]如何根据第一个值生成元组列表的笛卡尔连接? [复制]
【发布时间】:2019-04-22 00:30:01
【问题描述】:

我有一个(Int,String) 类型的元组列表,我想生成一个[String] 类型的列表,其中每个字符串都是具有相同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 值置换元组:

possible_keys :: [(Int,String)] -> [String]
possible_keys subkeys = [ key | keysize <- keysizes, key<-keys]
  where keysizes = map (fst) subkeys
        keys = sequence (map (snd) subkeys)

有什么提示吗?

【问题讨论】:

  • @duplode 如果只有一个元组,则忽略该元组。如果有超过 2 个具有相同 int 值的元组,例如您的示例,它将给出 ["adx", "ady","adz","aex","aey","ayz","afx","afy" ,"afz","bex","bey"...]
  • 没关系——我只看过你的例子,并没有注意到你已经可以使用sequence 进行排列。
  • 是的,它循环正常,但我仍然找不到用其他元组而不是具有相同 int 值的元组过滤排列的方法

标签: haskell


【解决方案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 相同;不幸的是没有类似的@ 987654328@ 还在标准库中。sequenceAsequenceonly more general 相同。)

这可以缩小一点。第二函子定律允许我们组合fmap的连续使用:

possible_keys :: Ord k => [(k, [c])] -> [[c]]
possible_keys = concat . fmap (sequenceA . fmap snd)
    . groupBy ((==) `on` fst) . sortBy (comparing fst)

fmap 后跟sequenceAtraverse

possible_keys :: Ord k => [(k, [c])] -> [[c]]
possible_keys = concat . fmap (traverse snd)
    . groupBy ((==) `on` fst) . sortBy (comparing fst)

最后,fmap 后跟concat 在列表中是concatMap(或(=&lt;&lt;),但这在这里有点太神秘了):

possible_keys :: Ord k => [(k, [c])] -> [[c]]
possible_keys = concatMap (traverse snd)
    . groupBy ((==) `on` fst) . sortBy (comparing fst)

请注意,这将为只有一个元组的键生成长度为 1 的字符串 -- sequenceA ["abc"]["a","b","c"]。如果您不希望这样,您可以在 groupBy 之后立即使用 filter 元组组来摆脱只有一个元组的那些。

【讨论】:

  • 现在还有sortOn。不过,我想知道它是否足够聪明,不会为fst 这样的简单访问器做整个装饰-未装饰的事情。可能不会。
  • 是的,同时想到了。 :) 那真不幸;程序员需要关心的细节越多,情况就越糟糕。我在这里是激进分子;我想看到一种语言,例如序列,编译器本身会根据需要选择列表或树或数组或其他任何东西。 (虽然我没有建造它......:))。
  • @WillNess 确实很不幸。我觉得“sortOn”这个名字对于这样一个特殊用途的功能来说太吸引人了……
  • @WillNess,duplode,有一个功能可以完成这项工作,但它被埋在GHC.ExtssortWith
  • @dfeuer 感谢您的指点。那里还有一个排序groupWith
猜你喜欢
  • 2022-11-17
  • 2017-02-25
  • 2013-11-16
  • 2021-10-22
  • 2011-03-01
  • 2021-05-06
  • 1970-01-01
  • 2016-10-08
  • 2020-07-13
相关资源
最近更新 更多