使用另一个列表中具有匹配构造函数的项替换列表中的项

时间:2014-10-21 16:32:07

标签: haskell

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

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']

有什么建议吗?

4 个答案:

答案 0 :(得分:2)

借用PetrPudlá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'。

答案 1 :(得分:0)

您可以创建一个替换项目的功能:

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中的相关替换。当然,如果在X列表中引入了更多Yb s,那么最后一个将在最后使用。

Your live example Another live example

答案 2 :(得分:0)

首先,您需要一种方法来确定使用了哪种构造函数:

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 :(得分:0)

对于给定的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中的每种类型相关。在这种方法中,每种类型的最新出现将保留在替换列表中。