【问题标题】:Replace items from a list with items with matching constructors in another list将列表中的项目替换为另一个列表中具有匹配构造函数的项目
【发布时间】:2014-10-22 19:37:42
【问题描述】:

为了简化我面临的问题,假设以下数据类型:

data Item = X Int | Y Char deriving (Eq, Show..)

还有两个列表

let a = [X 1, Y 'g']
let b = [X 2]

我需要使用相同的构造函数将a 中的所有项目替换为b 中的第一个(或任何)项目。所以结果是:[X 2, Y 'g']

有什么建议吗?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    您可以尝试从 Petr Pudlák 的 answer 中借鉴想法:

    {-# LANGUAGE DeriveDataTypeable #-}
    
    import Data.Data
    import Data.Function (on)
    import Data.List (nubBy, find)
    import Data.Maybe (fromMaybe)
    
    data Item = X Int | Y Char
      deriving (Eq, Show, Typeable, Data)
    
    a = [X 1, Y 'g']
    b = [X 2]
    
    main :: IO ()
    main = print $ map replace a
      where b' = nubBy (on (==) toConstr) b -- remove duplicates
            replace x = fromMaybe x $ find (on (==) toConstr x) b'
    

    您也可以跳过删除 b 中的重复项并在最后一行使用 b 而不是 b'。

    【讨论】:

      【解决方案2】:

      首先你需要一种方法来确定使用了什么构造函数:

      isX :: Item -> Bool
      isX (X _) = True
      isX _ = False
      
      -- If you have more than 2 constructors you'll have to write them all like isX
      isY :: Item -> Bool
      isY = not . isX
      

      以及获取每种构造函数第一个值的方法

      import Data.Maybe
      
      firstX :: [Item] -> Maybe Item
      firstX = listToMaybe . filter isX
      
      firstY :: [Item] -> Maybe Item
      firstY = listToMaybe . filter isY
      

      然后是替换物品的方法

      replaceItem :: Item -> Maybe Item -> Item
      replaceItem = fromMaybe
      
      replaceItems :: [Item] -> Maybe Item -> Maybe Item -> [Item]
      replaceItems [] _ _ = []
      replaceItems (item:items) x y =
          (if isX item
              then replaceItem item x
              else replaceItem item y) : replaceItems items x y
      

      但由于这只是一张地图:

      replaceXY :: Item -> Maybe Item -> Maybe Item -> [Item]
      replaceXY item x y =
          if isX item
              then replaceItem item x
              else replaceItem item y
      
      replaceItems items x y = map (\item -> replaceXY item x y) items
      

      最后你只需要将它与firstXfirstY 结合起来:

      replaceFrom :: [Item] -> [Item] -> [Item]
      replaceFrom a b =
          let x = firstX b
              y = firstY b
          in replaceXY a x y
      

      【讨论】:

        【解决方案3】:

        你可以只做一个函数来替换项目:

        specialReplace :: Item -> Item -> Item
        specialReplace (X x1) (X x2) = (X x1)
        specialReplace (Y y1) (Y y2) = (Y y1)
        specialReplace _ a = a
        

        然后:

        foldr (\el list -> map (specialReplace el) list) a b
        

        将在您的a 列表中运行,并相应地在b 中应用相关替换。当然如果b列表中引入更多Xs或Ys,那么最后使用最后一个。

        Your live exampleAnother live example

        【讨论】:

          【解决方案4】:

          对于给定的Item 和要替换的列表,请考虑,

          replace' :: Item -> [Item] -> [Item]
          replace' _ [] = []
          replace' (X i) ((X j):xs) = (X i) : replace' (X i) xs
          replace' (Y i) ((Y j):xs) = (Y i) : replace' (Y i) xs
          replace' r (x:xs) = x : replace' r xs
          

          其中每个模式与Item 中的每个类型相关。在这种方法中,每种类型的最新出现将保留在替换列表中。

          【讨论】:

            猜你喜欢
            • 2022-07-18
            • 1970-01-01
            • 2019-12-24
            • 1970-01-01
            • 1970-01-01
            • 2021-11-23
            • 2017-08-25
            • 2012-03-12
            • 2021-04-19
            相关资源
            最近更新 更多