Replace elements from the list with elements with corresponding constructors in another list

To simplify the task I came across, suppose this data type is:

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

and two lists

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

I need to replace all elements in a with the first (or any) element in b with the same constructor. Thus, the result will be: [X 2, Y 'g'] .

Any suggestions?

+6
source share
4 answers

Borrowing ideas from the answer of Peter Pudlak, you can try:

 {-# 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' 

You can also skip deleting duplicates in b and use b instead of b 'in the last line.

+2
source

You can simply execute the function to replace the elements:

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

and then:

 foldr (\el list -> map (specialReplace el) list) ab 

will be done through your list a and apply correlated substitutions in b accordingly. Of course, if more than X or Y added to list b , then the latter will be used at the end.

Your live example Another live example

0
source

First you need a way to determine which constructor was used:

 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 

And a method to get the first value of each type of constructor

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

Then you can replace the items

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

But since this is just a map:

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

And finally, you just need to combine this with firstX and firstY :

 replaceFrom :: [Item] -> [Item] -> [Item] replaceFrom ab = let x = firstX b y = firstY b in replaceXY axy 
0
source

For a given Item and a list to be replaced, consider <

 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 

in which each template refers to each type in Item . In this approach, the last substitution of each type will be stored in the replaced list.

0
source

Source: https://habr.com/ru/post/977041/


All Articles