user3354339
user3354339

Reputation: 11

Haskell:: how to compare/extract/add each element between lists

I'm trying to get each element from list of lists.

For example, [1,2,3,4] [1,2,3,4]

I need to create a list which is [1+1, 2+2, 3+3, 4+4]

list can be anything. "abcd" "defg" => ["ad","be","cf","dg"]

The thing is that two list can have different length so I can't use zip.

That's one thing and the other thing is comparing.

I need to compare [1,2,3,4] with [1,2,3,4,5,6,7,8]. First list can be longer than the second list, second list might be longer than the first list.

So, if I compare [1,2,3,4] with [1,2,3,4,5,6,7,8], the result should be [5,6,7,8]. Whatever that first list doesn't have, but the second list has, need to be output.

I also CAN NOT USE ANY RECURSIVE FUNCTION. I can only import Data.Char

Upvotes: 0

Views: 1245

Answers (5)

AndrewC
AndrewC

Reputation: 32455

Padding then zipping

You suggested in a comment the examples:

[1,2,3,4] [1,2,3] => [1+1, 2+2, 3+3, 4+0] 
"abcd" "abc" => ["aa","bb","cc"," d"]

We can solve those sorts of problems by padding the list with a default value:

padZipWith :: a -> (a -> a -> b) -> [a] -> [a] -> [b]
padZipWith def op xs ys = zipWith op xs' ys' where
     maxlen = max (length xs) (length ys)
     xs' = take maxlen (xs ++ repeat def)
     ys' = take maxlen (ys ++ repeat def)

so for example:

ghci> padZipWith 0 (+) [4,3] [10,100,1000,10000]
[14,103,1000,10000]
ghci> padZipWith ' ' (\x y -> [x,y]) "Hi" "Hello"
["HH","ie"," l"," l"," o"]

(You could rewrite padZipWith to have two separate defaults, one for each list, so you could allow the two lists to have different types, but that doesn't sound super useful.)

General going beyond the common length

For your first question about zipping beyond common length:

How about splitting your lists into an initial segment both have and a tail that only one of them has, using splitAt :: Int -> [a] -> ([a], [a]) from Data.List:

bits xs ys = (frontxs,frontys,backxs,backys) where
      (frontxs,backxs) = splitAt (length ys) xs
      (frontys,backys) = splitAt (length xs) ys

Example:

ghci> bits "Hello Mum" "Hi everyone else"
("Hello Mum","Hi everyo","","ne else")

You could use that various ways:

larger xs ys = let (frontxs,frontys,backxs,backys) = bits xs ys in
       zipWith (\x y -> if x > y then x else y) frontxs frontys ++ backxs ++ backys

needlesslyComplicatedCmpLen xs ys = let (_,_,backxs,backys) = bits xs ys in
       if null backxs && null backys then EQ
         else if null backxs then LT else GT
-- better written as   compare (length xs) (length ys)

so

ghci> larger "Hello Mum" "Hi everyone else"
"Hillveryone else"
ghci> needlesslyComplicatedCmpLen "Hello Mum" "Hi everyone else"
LT

but once you've got the hang of splitAt, take, takeWhile, drop etc, I doubt you'll need to write an auxiliary function like bits.

Upvotes: 0

Alexey Romanov
Alexey Romanov

Reputation: 170805

The thing is that two list can have different length so I can't use zip.

And what should the result be in this case?

CAN NOT USE ANY RECURSIVE FUNCTION

Then it's impossible. There is going to be recursion somewhere, either in the library functions you use (as in other answers), or in functions you write yourself. I suspect you are misunderstanding your task.

Upvotes: 2

Yuriosity
Yuriosity

Reputation: 1918

For your first question, you can use zipWith:

zipWith f [a1, a2, ...] [b1, b2, ...] == [f a1 b1, f a2 b2, ...]

like, as in your example,

Prelude> zipWith (+) [1 .. 4] [1 .. 4]
[2,4,6,8]

I'm not sure what you need to have in case of lists with different lengths. Standard zip and zipWith just ignore elements from the longer one which don't have a pair. You could leave them unchanged, and write your own analog of zipWith, but it would be something like zipWithRest :: (a -> a -> a) -> [a] -> [a] -> [a] which contradicts to the types of your second example with strings.

For the second, you can use list comprehensions:

Prelude> [e | e <- [1 .. 8], e `notElem` [1 .. 4]]
[5,6,7,8]

It would be O(nm) slow, though.

Upvotes: 1

thumphries
thumphries

Reputation: 248

For your second question (if I'm reading it correctly), a simple filter or list comprehension would suffice:

uniques a b = filter (not . flip elem a) b

Upvotes: 0

clancer
clancer

Reputation: 613

I believe you can solve this using a combination of concat and nub http://www.haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/Data-List.html#v%3anub which will remove all duplicates ...

nub (concat [[0,1,2,3], [1,2,3,4]])

you will need to remove unique elements from the first list before doing this. ie 0 (using the same functions)

Upvotes: 0

Related Questions