How can I join two lists into one complex list using mapA

G-d willing

Hello,
How can I merge 2 lists into one list where the first element in the merged list will be of type data that has both first elements from the two lists?
For example, I have the following 2 lists:
nums = [1,2,3,4,5]
letters = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]

I would like to have the result like so:
merged = [(1, ‘a’), (2, ‘b’), (3, ‘c’), (4, ‘d’), (5, ‘e’)]

I know how to do it using a recursive function, but I would like to know (and learn) if possible how to do it using the map function

Use zip (Module Prelude — Daml SDK 2.5.0 documentation):

import DA.Assert
import Daml.Script

testZip : Script ()
testZip =
  let nums = [1,2,3,4,5]
      letters = ["a", "b", "c", "d", "e"]
      merged = zip nums letters
  in merged === [(1, "a"), (2, "b"), (3, "c"), (4, "d"), (5, "e")]
1 Like

Thank you @dtanabe,
Basically in my situation, one of the lists is a bit more complex and not just a simple list of primitive type.
A similar situation is like the following:

  data ComplexInt = ComplexInt
    with
      num : Int
      name : Text
  deriving (Eq, Show)

  data MoreComplexInt = MoreComplexInt
    with
      complexInt : ComplexInt
      num2 : Int
    deriving (Eq, Show)

type FirstList = [ComplexInt]
type SecondList = [Int]
type ResultList = [MoreComplexInt]

I can write the following function:

funcMerge : FirstList -> SecondList -> ResultList
funcMerge [] [] = []
funcMerge [complexInt] [num2] = [MoreComplexInt with ..]
funcMerge (complexInt::restComplex) (num2::restNums) =
  let
    firstResult = MoreComplexInt with ..
    restResults = funcMerge restComplex restNums
  in firstResult :: restResults
funcMerge _ _ = []

Can it be done using map?

It sounds like you should probably use zipWith instead. But note that you can use zip and map regardless of whether the lists are primitive or complex. Given this sample data model and a sample function that “merges” a Person and their shopping Cart to create an Order:

data Person = Person with
    name : Text
    address : Text
  deriving (Eq, Show)

data Cart = Cart with
    items : [Item]
  deriving (Eq, Show)

data Item = Item with
    productName : Text
    quantity : Integer
  deriving (Eq, Show)

data Order = Order with
    name : Text
    address : Text
    items : [Item]
  deriving (Eq, Show)

You can map over the result from a zip:

-- makeOrder takes a tuple as its argument
makeOrder : (Person, Cart) -> Order
makeOrder t = Order with
  name = t._1.name
  address = t._1.address
  items = t._2.items

makeOrders : [Person] -> [Cart] -> [Order]
makeOrders people carts = map makeOrder $ zip people carts

But usually when you need to map and zip at the same time, you’re better off using zipWith, which takes a function that takes two args, followed by two lists:

-- here makeOrder has two parameters instead of taking a tuple
makeOrder : Person -> Cart -> Order
makeOrder person cart = Order with
  name = person.name
  address = person.address
  items = cart.items

-- then the implementation here is a bit simpler
makeOrders : [Person] -> [Cart] -> [Order]
makeOrders people carts = zipWith makeOrder people carts

-- you could also write `makeOrders` much more simply
makeOrders = zipWith makeOrder
1 Like

Thank you very much for the answer. It helped a lot.

1 Like