a!map complex merging

Input map

local!inputMap:{
a!map(pagenum: 1,fieldname: "Name", fieldValue:"Appian",docid:1),
a!map(pagenum: 1,fieldname: "howold", fieldValue:15, docid:1),
a!map(pagenum: 1,fieldname: "Name", fieldValue:"VB",docid:1),
a!map(pagenum: 1,fieldname: "howold", fieldValue:12, docid:1),
a!map(pagenum: 2,fieldname: "Name", fieldValue:"Java",docid:1),
a!map(pagenum: 2,fieldname: "howold", fieldValue:25, docid:1),
a!map(pagenum: 1,fieldname: "Name", fieldValue:"COBOL",docid:2),
a!map(pagenum: 1,fieldname: "howold", fieldValue:45, docid:2),
a!map(pagenum: 2,fieldname: "Name", fieldValue:"PL1",docid:2),
a!map(pagenum: 2,fieldname: "howold", fieldValue:55, docid:2)
},

Desired output map


local!outputMap :{
a!map(pagenum: 1 , Name: "Appian", howold: 15, docid:1),

a!map(pagenum: 1 , Name: "VB", howold: 12, docid:1),
a!map(pagenum: 2 , Name: "Java", howold: 25, docid:1),
a!map(pagenum: 1 , Name: "COBOL", howold: 45, docid:2),
a!map(pagenum: 2 , Name: "PL1", howold: 55, docid:2)
},

Is this possible ?

  Discussion posts and replies are publicly visible

  • 0
    Certified Lead Developer

    Sure. The trick here is to create a new map and add the fields iteratively. The reduce function allows to apply the same function and modify the data on the go. The "_" is a placeholder at design time and replaced by the actual data at runtime.

    docs.appian.com/.../expression-advanced-evaluation.html

    a!localVariables(
      local!input: {
        a!map(pagenum: 1,fieldname: "Name", fieldValue:"Appian",docid:1),
        a!map(pagenum: 1,fieldname: "howold", fieldValue:15, docid:1),
        a!map(pagenum: 2,fieldname: "Name", fieldValue:"Java",docid:1),
        a!map(pagenum: 2,fieldname: "howold", fieldValue:25, docid:1)
      },
      a!forEach(
        items: union(local!input.pagenum, local!input.pagenum),
        expression: a!localVariables(
          local!rows: index(local!input, where(local!input.pagenum = fv!item), {}),
          reduce(
            a!update(_, _, _),
            a!map(pagenum: fv!item),
            merge(local!rows.fieldname, local!rows.fieldValue)
          )
        )
      )
    )

  • For the updated input map, this change in the Stefan's code should work

    a!localVariables(
      local!input:{
        a!map(pagenum: 1,fieldname: "Name", fieldValue:"Appian",docid:1),
        a!map(pagenum: 1,fieldname: "howold", fieldValue:15, docid:1),
        a!map(pagenum: 2,fieldname: "Name", fieldValue:"Java",docid:1),
        a!map(pagenum: 2,fieldname: "howold", fieldValue:25, docid:1),
        a!map(pagenum: 1,fieldname: "Name", fieldValue:"COBOL",docid:2),
        a!map(pagenum: 1,fieldname: "howold", fieldValue:45, docid:2),
        a!map(pagenum: 2,fieldname: "Name", fieldValue:"PL1",docid:2),
        a!map(pagenum: 2,fieldname: "howold", fieldValue:55, docid:2)
      },
      local!uniqueDocRows: a!forEach(
        union(local!input.docid,local!input.docid),
        index(
          local!input,
          where(local!input.docid = fv!item),
          {}
        )
      ),
      a!flatten(a!forEach(
        local!uniqueDocRows,
        a!localVariables(
          local!parentItem: fv!item,
         a!forEach(
        items: union(fv!item.pagenum, fv!item.pagenum),
        expression: a!localVariables(
          local!rows: index(local!parentItem, where(local!parentItem.pagenum = fv!item), {}),
          reduce(
            a!update(_, _, _),
            a!map(pagenum: fv!item),
           merge({local!rows.fieldname,"docid"}, {local!rows.fieldValue, union(local!rows.docid, local!rows.docid)})
         )
      )
    )
    )
    )
    )
    )

    Ps: Wait for Stefan to post the updated solution with better and less complex logic Slight smile

  • Your solution works but it skips first 2 rows , can't see a!map(pagenum: 1 , Name: "Appian", howold: 15, docid:1),in the output

  • +1
    Certified Senior Developer
    in reply to ravib0008

    How will it work if you keep on changing inputMap in the question again and again after we post a solution and don't even let us know about that???

    For others to know, this was the inputMap updated by you when I answered (for which it works perfectly), before that when Stefan answered it was something else.

    From the current map how can you identify that howold:15 is related to Name: "Appian" and not Name: "VB"?

    If this list of map is going to remain in the same order i.e., "howold" map will come after every "Name" map, then this code can help.

    a!localVariables(
      local!input:{
        a!map(pagenum: 1,fieldname: "Name", fieldValue:"Appian",docid:1),
        a!map(pagenum: 1,fieldname: "howold", fieldValue:15, docid:1),
        a!map(pagenum: 1,fieldname: "Name", fieldValue:"VB",docid:1),
        a!map(pagenum: 1,fieldname: "howold", fieldValue:12, docid:1),
        a!map(pagenum: 2,fieldname: "Name", fieldValue:"Java",docid:1),
        a!map(pagenum: 2,fieldname: "howold", fieldValue:25, docid:1),
        a!map(pagenum: 1,fieldname: "Name", fieldValue:"COBOL",docid:2),
        a!map(pagenum: 1,fieldname: "howold", fieldValue:45, docid:2),
        a!map(pagenum: 2,fieldname: "Name", fieldValue:"PL1",docid:2),
        a!map(pagenum: 2,fieldname: "howold", fieldValue:55, docid:2)
      },
      local!uniqueDocRows: a!forEach(
        union(local!input.docid,local!input.docid),
        index(
          local!input,
          where(local!input.docid = fv!item),
          {}
        )
      ),
      a!flatten(a!forEach(
        local!uniqueDocRows,
        a!localVariables(
          local!parentItem: fv!item,
          a!forEach(
            items: union(fv!item.pagenum, fv!item.pagenum),
            expression: a!localVariables(
              local!Pagenum: fv!item,
              local!rows: index(local!parentItem, where(local!parentItem.pagenum = fv!item), {}),
              local!NameRows: index(local!rows,wherecontains("Name", local!rows.fieldname),null),
              local!howoldRows:  index(local!rows,wherecontains("howold", local!rows.fieldname),null),
              local!finalRows: merge(local!NameRows, local!howoldRows),
              a!forEach(
               local!finalRows,
              reduce(
                a!update(_, _, _),
                a!map(pagenum: local!Pagenum),
                merge({fv!item.fieldname,"docid"}, {fv!item.fieldValue, union(fv!item.docid, fv!item.docid)})
              )
              )
            )
          )
        )
      )
      )
    )

  • 0
    Certified Lead Developer
    in reply to ravib0008

    It also might help to explain the purpose of this. Then we can develop a more generic algorithm. This feels like you want to translate a list of key-values into a column format.

  •  Thanks, that fixed it. Sorry the requirements changed and I had to modify inputmap.

    @stefan , use case is if u scan a set of documents with multiple pages where u want to extract certain matching key-value pairs ..e.g. document 1 , with 2 pages has multiple matches of certain key/value pairs in terms of fieldName/fieldvalue on page 1 and page 2 .. 

  • 0
    Certified Senior Developer
    in reply to ravib0008

    You just sent an email to some Sanchita Gupta twice in a row stating that he/she has been mentioned in this thread which they don't even have any clue about.

    Also, it helps if you can mark the answer as verified Slight smile

  • 0
    Certified Lead Developer
    in reply to ravib0008

    Hm ... sounds like a generic algorithm might help you. You can use the reduce() function to maintain a list of items identified by some unique key. Then add a value to an existing item, or add a new item.