Haskell, 2 list to list of tuples pointwise

Viewed 129

List1 = [a,b]

List2 = [1,2]

I want the result list to look like this [a1, b2]

Currently i have:

[(v,a) | v <- List1, a <- List2 ]

but that gives [a1, a2, b1, b2]

3 Answers

What you need is zip :: [a] -> [b] -> [(a, b)]. This iterates concurrently over the two lists, and makes 2-tuples for these items.

For example:

Prelude> zip ['a', 'b'] [1,2]
[('a',1),('b',2)]
Prelude> zip [1,4,2,5] "bacd"
[(1,'b'),(4,'a'),(2,'c'),(5,'d')]

zip will stop from the moment that one of the two lists is exhausted. So if one of the lists is infinite, and the other is finite, then the result will be a finite list for example.

You can also make use of the ParallelListComp extension to iterate over collections in parallel in a list comprehension expression:

{-# LANGUAGE ParallelListComp #-}

myzip :: [a] -> [b] -> [(a, b)]
myzip la lb = [(a, b) | a <- la | b <- lb ]

but here it does not make much sense to do that. If you want to do more "complex" zipping, then this extension is probably more useful.

So, you want a function of type [Char] -> [Int] -> [(Char, Int)]. Let me introduce you to Hoogle:

zip :: [a] -> [b] -> [(a, b)]
base Prelude Data.List GHC.List GHC.OldList, Cabal Distribution.Compat.Prelude.Internal, ghc GhcPrelude
. zip takes two lists and returns a list of corresponding pairs.

zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]

If one input list is short, excess elements of the longer list are discarded:

zip [1] ['a', 'b'] = [(1, 'a')]
zip [1, 2] ['a'] = [(1, 'a')]

zip is right-lazy:

zip [] _|_ = []
zip _|_ [] = _|_

zip is capable of list fusion, but it is restricted to its first list argument and its resulting list.
zip :: () => [a] -> [b] -> [(a, b)]
hspec Test.Hspec.Discover, base-compat Prelude.Compat, protolude Protolude, rio RIO.List RIO.Prelude, universum Universum.List.Reexport, dimensional Numeric.Units.Dimensional.Prelude, rebase Rebase.Prelude, ghc-lib-parser GhcPrelude, xmonad-contrib XMonad.Config.Prime, stack Stack.Prelude, LambdaHack Game.LambdaHack.Core.Prelude Game.LambdaHack.Core.Prelude, mixed-types-num Numeric.MixedTypes.PreludeHiding, heart-core Heart.Core.Prelude, intro Intro, hledger-web Hledger.Web.Import, tonalude Tonalude, brittany Language.Haskell.Brittany.Internal.Prelude
zip takes two lists and returns a list of corresponding pairs.

zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]

If one input list is short, excess elements of the longer list are discarded:

zip [1] ['a', 'b'] = [(1, 'a')]
zip [1, 2] ['a'] = [(1, 'a')]

zip is right-lazy:

zip [] _|_ = []
zip _|_ [] = _|_

zipExact :: Partial => [a] -> [b] -> [(a, b)]
safe Safe.Exact

zipExact xs ys =
| length xs == length ys = zip xs ys
| otherwise              = error "some message"

zip :: () => [a] -> [b] -> [(a, b)]
numeric-prelude NumericPrelude NumericPrelude.Base, distribution-opensuse OpenSuse.Prelude
zip takes two lists and returns a list of corresponding pairs. If one input list is short, excess elements of the longer list are discarded. zip is right-lazy:

zip [] _|_ = []

(+*+) :: [a] -> [b] -> [(a, b)]
universe-base Data.Universe.Helpers

cartesianProduct (,)
...

The first hit

One other way can also be achieved by the ZipList type which is defined in Control.Applicative to lower the undeterministic approach to a simpler one to one mapping for the List types.

All you need is to import Control.Applicative and use the ZipList data constructor.

λ> getZipList $ (,) <$> ZipList "ab" <*> ZipList [1,2]
[('a',1),('b',2)]

getZipList is an accessor which extracts a proper list from the ZipList type.

Related