Home > Net >  Elegant way to mask-merge two strings in Haskell
Elegant way to mask-merge two strings in Haskell

Time:12-10

For example if we have two strings "abc" and "1234" i want result "abc4" (the first string masks second). (If we draw them vertical it's like a wave comes from left and tuch chars)

             "a"  "1"            "a"
 wave ->     "b"  "2"   result   "b" 
             "c"  "3"            "c"
                  "4"            "4"  

I start with this solution with Haskell

slice from to xs = take (to - from   1) (drop from xs)
merge l1 l2 = if length l2 > length l1 
                then l1    slice (length l1) (length l2) l2 
                else l1

Can you please provide some more elegant\compact solutions.

CodePudding user response:

You just need a special merge function

> let merge [] ys = ys
|     merge xs [] = xs
|     merge (x:xs) (y:ys) = x : merge xs ys

or using drop

> let merge2 x y = x    drop (length x) y

CodePudding user response:

You want kind of a "zipLongest", and transpose is kind of like that:

maskMerge1 :: [b] -> [b] -> [b]
maskMerge1 as bs  =  map head $ transpose [as,bs]
              -- or:
              --        head <$> transpose [as,bs]

This is pretty compact and elegant (with big thanks to @leftaroundabout for the comments!).

Looking from above,

      "abc"         ['a' ,'b' ,'c'     ]
      "1234"        ['1' ,'2' ,'3' ,'4']
     --------      ------------------
                    ["a1","b2","c3","4"]
     --------      ------------------
      "abc4"        ['a' ,'b' ,'c' ,'4']

The code with length in the other answer also works, and even for an infinite x despite calling the dreaded length on it, but it will retain the whole of x in memory because of calling the length on it.

  • Related