How to achive foldl operation for Map data

Could someone guide me to the solution of below case.

Example: There is a mapList on the template which of type Map Text [List]

Now i want to append data to the list after satisying some rules, for this i need a way to concatinate original map i.e., mapList with new data everytime

and the return value should be mapList with new List of data appended


Map on template --> mapList : Map Text [VersionList]
VersionList is a Record --> VersionList =  [VersionList with value = 1000]

forA VersionList(\version -> do
        let value = version.value
        if (value == "1000" ) then do
            let concateValues = VersionList ++ [2000] 
             mapList = M.insert( "amount" concatValue)
            return ()                                                                                                    
       else do
            return () 

        ) 

Output : After for loop expecting mapList to be as (amount, [1000,2000])

Hi @Sneha, what is the type of versionList? Your example doesn’t seem to reference mapList so I’m slightly unclear on where it fits in.

Hi @cocreature, I have edited the example. Hope this would be clear now.

Here is one solution that satisfies the input you provided. I am not quite sure I understood your requirements correctly so if you were looking for something else, let us know:

module Main where

import Daml.Script
import DA.Assert
import DA.Next.Map (Map)
import qualified DA.Next.Map as Map

data Version = Version with
    value : Text
  deriving (Eq, Show)

processMap : Map Text [Version] -> Map Text [Version]
processMap mapList = 
  Map.fromList 
    (map (\(mapKey, versionList) -> (mapKey, processList versionList))
         (Map.toList mapList))

processList : [Version] -> [Version]
processList versionList =
  concatMap f versionList
  where
    f version
      | version.value == "1000" = [version, Version "2000"]
      | otherwise = [version]

test = script do
  -- Original example
  processMap (Map.fromList [("amount", [Version "1000"])])
          === Map.fromList [("amount", [Version "1000", Version "2000"])]

  -- 2000 is inserted directly after 1000 not at the very end
  processMap (Map.fromList [("amount", [Version "1000", Version "3000"])])
          === Map.fromList [("amount", [Version "1000", Version "2000", Version "3000"])]

  -- This applies the same to all keys not just amount
  processMap (Map.fromList [("notamount", [Version "1000", Version "3000"])])
          === Map.fromList [("notamount", [Version "1000", Version "2000", Version "3000"])]

Okay @cocreature Thank you for this approach.

May be I have complicated the question. Below is the simple example of the question (Additive operation on Map). Could you please help me.

Lets say there is a global map MapA, Now want to concat MapA with (MapB or MapC or Map D and so on) and add the result to MapA

MapA = MapA ++ MapB

To achieve the above you can use the merge function in DA.Next.Map module.

1 Like

Thank you @Luciano. I am trying to use the merge key but sorry unable to understand the structure.

merge

: MapKey k => (k -> a -> Optional c) -> (k -> b -> Optional c) -> (k -> a -> b -> Optional c) -> Map k a -> Map k b -> Map k c

How to read and understand the structure.
Is there any example for merge key where I can refer to?

merge is a generalized version of union. Whereas union always prefers elements of the second map over elements from the first if a key occurs in both, merge allows you to provide 3 functions to customize how the maps should be merged:

  1. The first function is used if the key only occurs in the first map. Returning None means that such elements will be discarded.
  2. The second function is used if the key only occurs in the second map. Same behavior for None.
  3. The third function is used if the key occurs in both maps. You can define how the values should be combined (e.g., if you have numbers, maybe adding them is the right thing to do).

Thank you @cocreature for the detail explaination.

Here’s a small code snippet that may clarify how to use some of the DA.Next.Map functions:

module Main where

import Daml.Script
import qualified DA.Next.Map as Map

setup : Script ()
setup = script do
  let map1 = Map.fromList [(1, "a"), (2, "b")]
  let map2 = Map.fromList [(2, "c"), (3, "d")]
  assert (
    Map.insert 5 "hello!" map1
    ==
    Map.fromList [(1, "a"), (2, "b"), (5, "hello!")]
    )
  assert (
    Map.insert 1 "changed!" map1
    ==
    Map.fromList [(1, "changed!"), (2, "b")]
    )
  assert (
    Map.delete 2 map1
    ==
    Map.fromList [(1, "a")]
    )
  assert (
    Map.union map1 map2
    ==
    Map.fromList [(1, "a"), (2, "b"), (3, "d")]
    )
  assert (
    Map.merge (\k v -> Some $ "from 1: " <> v)
              (\k v -> Some $ "from 2: " <> v)
              (\k v1 v2 -> Some $ "from both: " <> v1 <> ", " <> v2)
              map1
              map2
    ==
    Map.fromList [(1, "from 1: a"),
                  (2, "from both: b, c"),
                  (3, "from 2: d")]
    )