【问题标题】:Removing conjugate tuples from a list in Haskell从 Haskell 的列表中删除共轭元组
【发布时间】:2017-04-22 22:20:50
【问题描述】:

我有一个元组列表。每个元组也是一个元组。对于每个外部元组,我都有一个共轭元组。我的意思是,如果我在列表中有 (a,b),那么我也有 (b,a)。我想要的是从列表中删除共轭元组。

这里给你一个我的清单的具体例子:

[((1,2,1,0),(5,2,1,0)),((2,4,4,0),(2,5,4,0)),((2,5,4,0),(2,4,4,0)),((3,1,1,0),(3,3,2,0)),((3,3,2,0),(3,1,1,0)),((5,1,7,0),(8,1,7,0)),((5,2,1,0),(1,2,1,0)),((5,5,8,0),(8,5,8,0)),((5,6,6,0),(8,6,8,0)),((5,9,9,0),(8,9,9,0)),((6,3,5,0),(6,8,9,0)),((6,8,9,0),(6,3,5,0)),((7,7,6,0),(9,7,6,0)),((8,1,7,0),(5,1,7,0)),((8,5,8,0),(5,5,8,0)),((8,6,8,0),(5,6,6,0)),((8,9,9,0),(5,9,9,0)),((9,7,6,0),(7,7,6,0))]

去掉共轭元组后的结果应该是:

[((1,2,1,0),(5,2,1,0)),((2,4,4,0),(2,5,4,0)),((3,1,1,0),(3,3,2,0)),((5,1,7,0),(8,1,7,0)),((5,5,8,0),(8,5,8,0)),((5,6,6,0),(8,6,8,0)),((5,9,9,0),(8,9,9,0)),((6,3,5,0),(6,8,9,0)),((7,7,6,0),(9,7,6,0)),]

我已经尝试了几个小时没有成功。任何帮助将不胜感激。

【问题讨论】:

  • "每个元组也是一个元组。"你的意思是每个元组也由元组组成。
  • 这是家庭作业吗?那就是你想要一个提示还是你想要一个解决方案?
  • 是的。可能是我发布的例子比我的措辞更好:)
  • @jpath :不,这不是家庭作业 :) 我快 60 岁了。我正在尝试解决拼图 sudoko,我需要删除重复项。
  • @jpath:如果我的列表看起来很神秘,那么这些代表拼图 sudoko 中的单元格。每个单元格的类型为 (Int,Int,Int,Int),表示单元格的行、列、区域和值。我写了一个给定网格的函数,我获得了具有相同潜在值的单元格。这个例子就是这样一个单元格的列表。

标签: list haskell tuples


【解决方案1】:

“元组的每个元素也是一个元组”

removeConj xs = foldl f [] xs
  where f b a = if (elem (snd a, fst a) b) then b else (a:b) 

【讨论】:

  • 好的,谢谢。但我试过了,它给了我相同的列表,即它没有删除共轭。
  • 是的,它奏效了。谢谢。有趣的是,结果列表的顺序与 jpath 解决方案生成的列表相反。我想我可以通过应用 reverse 函数来保留顺序。
  • 附带说明一下,Haskell 中是否有测量两个函数执行任务所需的时间。例如,如何比较 ja 解决方案比 jpath 解决方案快还是慢?
  • 我知道使用 ghci 对函数进行基准测试并不准确。但是,我使用 :set +s 来比较我得到的解决方案。结果是:(0.06 秒,272,840 字节)——对于 removeConj(0.07 秒,277,416 字节)——对于 nubTuples 附注:我在我的示例中使用了这个,它没有提供真实的指标。
【解决方案2】:

首先我们可以将类型概括为:

nubTuples :: Eq a => [(a,a)] -> [(a,a)]

但是,为了让事情变得更高效、更简单,我们还要为a 申请一个Ord 实例。为什么这会让事情变得更容易?因为现在我们可以将元组转换为有序的范式。然后我们可以简单地nub . sort。下面的实现实际上只是根据该表示进行排序和小结,因此nubTuples [(2,1)] = [(2,1)] 而不是[(1,2)]。

import Data.List (sortOn, nubBy)
import Data.Tuple (swap)

nubTuples :: Ord a => [(a,a)] -> [(a,a)]
nubTuples = nubBy unorderedCompare . sortOn orderTuple
  where orderTuple (x,y)
          | x < y = (x,y)
          | otherwise = (y,x)
        unorderedCompare x y = x == y || swap x == y

请注意,这会更改顺序并删除重复项:

nubTuples [(3,4),(1,2),(1,2)] = [(1,2),(3,4)]

至于更改顺序,我们可以使用 discrimination 包中的 Data.Discrimination 中的 nubWith 函数来解决这个问题。那么我们的代码会变成下面这样:

 import Data.Discrimination (nubWith, Grouping)

 nubTuples :: (Ord a, Grouping a) => [(a,a)] -> [(a,a)]
 nubTuples = nubWith orderTuple
   where orderTuple (x,y)
           | x < y = (x,y)
           | otherwise = (y,x)

这不需要排序,保持顺序不变并且最大限度地保持惰性(这通常对性能非常重要)。但它仍然会删除重复项。

您可以简单地为您的任何类型派生一个Grouping 实例,如下所示:

{-# LANGUAGE DeriveGeneric #-}
import Data.Discrimination
import GHC.Generics

data A = A deriving Generic
instance Grouping A

请注意,对于 4 元组,没有 Grouping 的实例。这将是一种解决方法:

nubFourTuples :: (Grouping a, Ord a, Grouping b, Ord b,
                  Grouping c, Ord c, Grouping d, Ord d)
              => [((a,b,c,d),(a,b,c,d))] -> [((a,b,c,d),(a,b,c,d))]
nubFourTuples = (fmap . both) reassociate . nubTuples . (fmap . both) associate
   where associate (w,x,y,z) = ((w,x),(y,z))
         reassociate ((w,x),(y,z)) = (w,x,y,z)
         both f (x,y) = (f x, f y)

【讨论】:

  • 非常感谢@jpath。有效。结果列表的顺序对我来说并不重要。
  • @HassanShahin 欢迎您。我还添加了另一个版本来保持顺序并具有懒惰的额外好处。
  • 是的。我注意到。再次感谢@jpath
  • 这很棒。但是你正在转向更高级的东西。我只是一个老初学者:)。非常感谢。
  • 是的,我在写join bimap 和nubFourTuples 这么长的类型时已经感到有点内疚了。整个discrimination 对于初学者来说可能已经太多了。
猜你喜欢
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 2022-01-18
相关资源
最近更新 更多