Merging the elements of two nested lists with Haskell - list

I want to append lists in one list and lists in a second list.
Using concat creates one list of all elements, while zip seems to combine the two nested lists into a single nested list without combining the child lists.
let x = [["one", "two"],["five", "six"], ["nine", "ten"]]
let y = [["three", "four"],["seven", "eight"], ["eleven", "twelve"]]
Should become
[["one", "two", "three", "four"], ["five", "six", "seven", "eight"], ["nine", "ten", "eleven", "twelve"]]
How do I achieve the above result? My hunch is to use map though I have been unsuccessful.

In some languages like Scheme map can accept any number of lists, but in Haskell, the binary map has its own name, zipWith:
zipWith (++) x y
will do what you wanted.
How to get there, playing at the REPL:
> zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
-- BTW these are not lists, but tuples
> zipWith (,) x y -- same thing as zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
> zipWith (\a b -> (a,b)) x y -- same thing as the above
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
> zipWith (\a b -> [a,b]) x y -- not the same thing as the above
[[["one","two"],["three","four"]],[["five","six"],["seven","eight"]],[["nine","ten"],["eleven","twelve"]]]
> zipWith (\a b -> concat [a,b]) x y -- success!
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]
> zipWith (\a b -> a ++ b) x y -- equivalent to the above
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]
> zipWith (++) x y -- finally, simplified.
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]
But you could also have used map as you wanted, to process the output of zip:
> zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
> map id $ zip x y
[(["one","two"],["three","four"]),(["five","six"],["seven","eight"]),(["nine","ten"],["eleven","twelve"])]
> map (\(a,b) -> a ++ b) $ zip x y -- the same as zipWith (++)
[["one","two","three","four"],["five","six","seven","eight"],["nine","ten","eleven","twelve"]]
Another way of achieving this is by using transpose which is kind of a zip itself:
map concat $ transpose [x,y]
This uses the same concat we saw above with two lists, which will now work on any number of sublists taken together in a single list, each from the originals (here, still two):
> transpose [x,y]
[[["one","two"],["three","four"]],[["five","six"],["seven","eight"]],[["nine","ten"],["eleven","twelve"]]]
Thus it is effortlessly extendable to processing any number of lists:
map concat $ transpose [x,y,z]
etc.

Related

Get the list of elements located in the even positions of initial list

The task is to use just one passthrough using foldr or foldl.
I use this decision:
evenOnly = fst . foldr (\x (y1, y2) -> (y2, x:y1)) ([],[])
Pretty good for finite lists. If I try evenOnly [1,2..] I'll got a fail. I know it's because of suspended caclulations, but how can I otherwise split the list or how to pass additional information about list positions or something to the calculations which begin at the end of the list?
You can use a lazy pattern ~(x1, y2):
> let evenOnly = fst . foldr (\x ~(y1, y2) -> (y2, x:y1)) ([],[])
> take 20 $ evenOnly [1..]
[2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40]
This is essentially the same as
> let evenOnly = fst . foldr (\x y -> (snd y, x:fst y)) ([],[])
which has the advantage of not forcing the pair constructor too early. That is, the lambda above will produce the (,) constructor in its output before it demands y (the "recursive" result).

Merge two List ["String",Float] into new list ["String",Float,Float]

We need to merge both lists into one who takes de number of frequency who a word appears in lists.
If we have:
`List 1 [("Hi", 0.45),("Steve", 0.0.5),("Bye",0.9)]...`
`List 2 [("Hello", 0.56), ("Steve", 0.6), ("Bye", 0.6)]..`
we want to get: [("Hi",0.45,0), ("Steve", 0.0.5, 0.6)...
mergeLists :: [(a,Float)] -> [(a,Float)] -> [(a,Float,Float)]
mergeLists v y = map (\x -> ( fst x, if not (elem (fst x) v) then 0
else 5 ,
if not (elem (fst x) v) then 5
else 0))y
Now we are doing by the following code, but we have a lot of problems to continue.
I'm trying to go forward the first list, if list2 doesn't contains the element write 0, otherwise write the frequency value of both lists into the new one.
This is easy when working with sorted lists. You need to augment the usual union function definition in that case, adapting it to your specific data type, like
mergeOrderedLists a b = go a b
where go a#((x,n):t) b#((y,m): ..... ) = case compare x y of
LT -> (x,n,0) : go t b
EQ -> ....... : go t r
GT -> ....... : go a r
go [] b = ......
......
you will have to complete the missing cases here (and for the empty lists too).
You will have to sort each of the argument lists to be able to use this function, to define what you describe.
Is it important to preserve the order of the lists? If not, you can do this with Data.Map. This gives you a map where the key is each word and the value is a [Float]. As a bonus you can combine as many lists this way as you want.
import Control.Arrow (second)
M.fromListWith (++) $ map (second (:[])) $ list1 ++ list2

Haskell add unique combinations of list to tuple

Say for example that I have a list like this
list = ["AC", "BA"]
I would like to add every unique combination of this list to a tuple so the result is like this:
[("AC", "AC"),("AC","BA"),("BA", "BA")]
where ("BA","AC") is excluded.
My first approach was to use a list comprehension like this:
ya = [(x,y) | x <- list, y <- list]
But I couldn't manage to get it to work, is there anyway to achieve my result by using list comprehensions?
My preferred solution uses a list comprehension
f :: [t] -> [(t, t)]
f list = [ (a,b) | theTail#(a:_) <- tails list , b <- theTail ]
I find this to be quite readable: first you choose (non-deterministically) a suffix theTail, starting with a, and then you choose (non-deterministically) an element b of the suffix. Finally, the pair (a,b) is produced, which clearly ranges over the wanted pairs.
It should also be optimally efficient: every time you demand an element from it, that is produced in constant time.
ThreeFx's answer will work, but it adds the constraint that you elements must be orderable. Instead, you can get away with functions in Prelude and Data.List to implement this more efficiently and more generically:
import Data.List (tails)
permutations2 :: [a] -> [(a, a)]
permutations2 list
= concat
$ zipWith (zip . repeat) list
$ tails list
It doesn't use list comprehensions, but it works without having to perform potentially expensive comparisons and without any constraints on what kind of values you can put through it.
To see how this works, consider that if you had the list [1, 2, 3], you'd have the groups
[(1, 1), (1, 2), (1, 3),
(2, 2), (2, 3),
(3, 3)]
This is equivalent to
[(1, [1, 2, 3]),
(2, [2, 3]),
(3, [3])]
since it doesn't contain any extra or any less information. The transformation from this form to our desired output is to map the function f (x, ys) = map (\y -> (x, y)) ys over each tuple, then concat them together. Now we just need to figure out how to get the second element of those tuples. Quite clearly, we see that all its doing is dropping successive elements off the front of the list. Luckily, this is already implemented for us by the tails function in Data.List. The first element in each of these tuples is just makes up the original list, so we know we can use a zip. Initially, you could implement this with
> concatMap (\(x, ys) -> map (\y -> (x, y)) ys) $ zip list $ tails list
But I personally prefer zips, so I'd turn the inner function into one that doesn't use lambdas more than necessary:
> concatMap (\(x, ys) -> zip (repeat x) ys) $ zip list $ tails list
And since I prefer zipWith f over map (uncurry f) . zip, I'd turn this into
> concat $ zipWith (\x ys -> zip (repeat x) ys) list $ tails list
Now, we can reduce this further:
> concat $ zipWith (\x -> zip (repeat x)) list $ tails list
> concat $ zipWith (zip . repeat) list $ tails list
thanks the eta-reduction and function composition. We could make this entirely pointfree where
> permutations2 = concat . ap (zipWith (zip . repeat)) tails
But I find this pretty hard to read and understand, so I think I'll stick with the previous version.
Just use a list comprehension:
f :: (Ord a) => [a] -> [(a, a)]
f list = [ (a, b) | a <- list, b <- list, a <= b ]
Since Haskell's String is in the Ord typeclass, which means it can be ordered, you first tell Haskell to get all possible combinations and then exclude every combination where b is greater than a which removes all "duplicate" combinations.
Example output:
> f [1,2,3,4]
[(1,1),(1,2),(1,3),(1,4),(2,2),(2,3),(2,4),(3,3),(3,4),(4,4)]

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
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.
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.
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
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)
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.

Haskell List Comprehension, where x can't be equal to an element of a list

I want to generate a list of tuples from a list of tuples, where the left part of the tuple only occurs on the left side in all the elements of the list.
Basically what I want is a more generalized version of the following:
[ (x,y) | (x,y) <- [(1,5),(5,2)], x /= 5, x /=2 ]
If [(1,5),(5,2)] would be a variable called list, then x can't be equal to any of the values of (map snd list). How do I put this condition the list comprehension? (or should I use something else? like filter?)
then x can't be equal to any of the values of (map snd list)
The direct translation of that is
x `notElem` map snd list
So you'd use something like
let xs = [(1,5),(5,2)] in [(x,y) | (x,y) <- xs, x `notElem` map snd xs]
If the list is long, that is not efficient, so then you could - if the type permits it, i.e. is an instance of Ord - build a set and check for membership in the set
let xs = [(1,5),(5,2)]
st = Data.Set.fromList (map snd xs)
in [(x,y) | (x,y) <- xs, not (Data.Set.member x st)]
to reduce the O(n²) complexity of the first to an O(n*log n) complexity.
Construct a Set of all the second elements (let's call it seconds), and then just filter by flip notMember seconds . fst. You could easily write this as a list comprehension if you really wanted to (but you'd just end up rewriting filter, so why do it?).