Skip to main content
daniels0002
September 26, 2024
Question

Trouble updating array with information from another array

  • September 26, 2024
  • 8 replies
  • 0 views

"I'm encountering an issue with updating an array in costAdjustments. The current code is setting the LengthOfMonth field to 6 for all items in the array, but I only want to update specific entries."

a!save(
  local!newEstimates2,
  local!newEstimates2: a!forEach(
    items: local!newEstimates,
    expression: a!update(
      fv!item,
      "costAdjustments",
      a!forEach(
        items: fv!item.costAdjustments,
        expression: a!update(fv!item, "LengthOfMonth", 6)
      )
    )
  )
)

This isn't exactly what I need. What I want to do is loop through newEstimates and pull data from local!uniqueContractPeriods, which contains three rows of data with the fields: period, periodType, startDate, endDate, noOfMonths, and noOfDays. When the contractPeriodNum in costAdjustments within newEstimates matches the period in uniqueContractPeriods, I want to update the LengthOfMonth in newEstimates with the value of noOfMonths from uniqueContractPeriods. Below is the code I've written.

a!save(  
              local!newEstimates2,  
              local!newEstimates2: a!forEach(  
                items: local!newEstimates,  
                expression: a!update(  
                  fv!item,  
                  "costAdjustments",  
                  a!forEach(  
                    items: local!uniqueContractPeriods,  
                    expression: if(  
                      fv!item.period = fv!item.costAdjustments.contractPeriodNum,  
                      a!update(  
                        fv!item,  
                        "LengthOfMonth",  
                        index(  
                          local!uniqueContractPeriods.noOfMonths,  
                          where(  
                            tostring(fv!item.period) = tostring(fv!item.costAdjustments.contractPeriodNum)  
                          )  
                        )  
                      ),  
                      fv!item  
                    )  
                  )  
                )  
              )  
            )

I am sure it is a simple fix, but I have been working on it for a long time, any assistance would be great.  Thank you.

    8 replies

    somasundaram.d
    September 27, 2024

    Try using update() and wherecontains() in tandem

    a!localVariables(
      local!newEstimates: {
        a!map(
          lengthOfMonth: 1,
          costAdjustments: a!map(contractPeriodNum: 11)
        ),
        a!map(
          lengthOfMonth: 2,
          costAdjustments: a!map(contractPeriodNum: 12)
        ),
        a!map(
          lengthOfMonth: 3,
          costAdjustments: a!map(contractPeriodNum: 13)
        )
      },
      local!uniqueContractPeriods: {
        a!map(
          period: 14,
          periodType: "TEST1",
          noOfMonths: 100,
          
        ),
        a!map(
          period: 11,
          periodType: "TEST2",
          noOfMonths: 200,
          
        ),
        a!map(
          period: 12,
          periodType: "TEST3",
          noOfMonths: 300,
          
        )
      },
      a!forEach(
        items: local!newEstimates,
        expression: if(
          a!isNullOrEmpty(
            wherecontains(
              fv!item.costAdjustments.contractPeriodNum,
              tointeger(local!uniqueContractPeriods.period)
            )
          ),
          fv!item,
          a!update(
            fv!item,
            "lengthOfMonth",
            cast(1,index(
              local!uniqueContractPeriods.noOfMonths,
              wherecontains(
                fv!item.costAdjustments.contractPeriodNum,
                tointeger(local!uniqueContractPeriods.period)
              ),
              null
            ))
          )
        )
      )
    )

    mikes0011
    Brainy
    September 27, 2024

    a!save() only executes in the context of a form component responding to a user interaction.  It's unclear whether you're working within this constraint correctly or not.

    Separately, both of your a!save() statements from your code boxes are constructed incorrectly.  Remember that the context of an a!save() statement has 2 parameters, "target" followed by "value", where the "data" parameter is evaluated then saved into the local or rule input variable named in "target".

    However in your code here, you name the target, "local!newEstimates2" in both cases, but then your "value" parameter nonsensically repeats "local!newEstimates2" as if it's a local variable declaration.  This both A) won't do anything, and B) should probably break (though i haven't tried).

    The "correct" way to do it, just to be clear, in the case of your top code example, would look more like this:

    a!save(
      local!newEstimates2,
      a!forEach(
        items: local!newEstimates,
        expression: a!update(
          fv!item,
          "costAdjustments",
          a!forEach(
            items: fv!item.costAdjustments,
            expression: a!update(fv!item, "LengthOfMonth", 6)
          )
        )
      )
    )

    This is a tad easier to visualize in terms of correct context if we flesh out the a!save() statement with parameter names (though this is of course optional) -

    a!save(
      target: local!newEstimates2,
      value: a!forEach(
        items: local!newEstimates,
        expression: a!update(
          fv!item,
          "costAdjustments",
          a!forEach(
            items: fv!item.costAdjustments,
            expression: a!update(fv!item, "LengthOfMonth", 6)
          )
        )
      )
    )

    daniels0002
    September 27, 2024

    Mike,  Thanks so much for a reply.  I got it to work but it still needs some changes.  I am kind of surprised that this worked.  I was trying to place all the updates within curly braces and it only worked for one update.  Can you look and suggest changes?  Thanks in advance for your help and suggestions.

    a!save(
                  local!newEstimates2,
                  a!forEach(
                    items: local!newEstimates,
                    expression: if(
                      a!isNullOrEmpty(
                        wherecontains(
                          fv!item.costAdjustments.contractPeriodNum,
                          tointeger(local!uniqueContractPeriods.period)
                        )
                      ),
                      fv!item,
                      a!update(
                        fv!item,
                        "costAdjustments",
                        a!update(
                          a!update(
                            a!update(
                              a!update(
                                fv!item.costAdjustments,
                                "lengthOfMonth",
                                cast(
                                  1,
                                  index(
                                    local!uniqueContractPeriods.noOfMonths,
                                    wherecontains(
                                      fv!item.costAdjustments.contractPeriodNum,
                                      tointeger(local!uniqueContractPeriods.period)
                                    ),
                                    null
                                  )
                                )
                              ),
                              "periodStartDate",
                              index(
                                local!uniqueContractPeriods.startDate,
                                wherecontains(
                                  fv!item.costAdjustments.contractPeriodNum,
                                  tointeger(local!uniqueContractPeriods.period)
                                ),
                                null
                              )
                            ),
                            "periodEndDate",
                            index(
                              local!uniqueContractPeriods.endDate,
                              wherecontains(
                                fv!item.costAdjustments.contractPeriodNum,
                                tointeger(local!uniqueContractPeriods.period)
                              ),
                              null
                            )
                          ),
                          "LengthOfDay",
                          index(
                            local!uniqueContractPeriods.noOfDays,
                            wherecontains(
                              fv!item.costAdjustments.contractPeriodNum,
                              tointeger(local!uniqueContractPeriods.period)
                            ),
                            null
                          )
                        )
                      )
                    )
                  )
                )

    mikes0011
    Brainy
    September 27, 2024

    Your code has a bunch of inefficiencies that make it difficult to parse (or really even read), let alone sacrifice processing power and efficiency.

    For instance: how many times are you manually re-doing the same identical "wherecontains(fv!item.cost..., tointeger(...))" statement?  I threw this into notepad and counted at least 5 instances of the exact same thing.  You should be abstracting things like this behind local variables, for 2-fold reasons: first, it means you only need to execute the code once, and second (perhaps more importantly), it cuts down on some of the hard-to-read code clutter.

    a!save(
      local!newEstimates2,
      
      a!forEach(
        items: local!newEstimates,
        expression: a!localVariables(
        
          /* do this calculation here, instead of 5 separate times for no reason */
          local!currentContractPeriodIndices: wherecontains(
            fv!item.costAdjustments.contractPeriodNum,
            tointeger(local!uniqueContractPeriods.period)
          ),
          
          if(
            a!isNullOrEmpty(local!currentContractPeriodIndices),
            fv!item,
            
            a!update(
              fv!item,
              "costAdjustments",
              a!update(
                a!update(
                  a!update(
                    a!update(
                      fv!item.costAdjustments,
                      "lengthOfMonth",
                      cast(
                        1,
                        index(
                          local!uniqueContractPeriods.noOfMonths,
                          local!currentContractPeriodIndices,
                          null
                        )
                      )
                    ),
                    "periodStartDate",
                    index(
                      local!uniqueContractPeriods.startDate,
                      local!currentContractPeriodIndices,
                      null
                    )
                  ),
                  "periodEndDate",
                  index(
                    local!uniqueContractPeriods.endDate,
                    local!currentContractPeriodIndices,
                    null
                  )
                ),
                "LengthOfDay",
                index(
                  local!uniqueContractPeriods.noOfDays,
                  local!currentContractPeriodIndices,
                  null
                )
              )
            )
          )
        )
      )
    )

    ...and further,
    a!save(
      local!newEstimates2,
      
      a!forEach(
        items: local!newEstimates,
        expression: a!localVariables(
          local!currentContractPeriodIndices: wherecontains(
            fv!item.costAdjustments.contractPeriodNum,
            tointeger(local!uniqueContractPeriods.period)
          ),
          
          /* we can also move this into a local variable so we don't have to do the same indexing over and over again */
          local!currentUniqueContractPeriod: index(
            local!uniqueContractPeriods,
            local!currentContractPeriodIndices,
            null
          ),
          
          if(
            a!isNullOrEmpty(local!currentContractPeriodIndices),
            fv!item,
            
            a!update(
              fv!item,
              "costAdjustments",
              
              a!update(
                a!update(
                  a!update(
                    a!update(
                      fv!item.costAdjustments,
                      "lengthOfMonth",
                      tointeger(local!currentUniqueContractPeriod.noOfMonths)
                    ),
                    "periodStartDate",
                    local!currentUniqueContractPeriod.startDate
                  ),
                  "periodEndDate",
                  local!currentUniqueContractPeriod.endDate
                ),
                "LengthOfDay",
                local!currentUniqueContractPeriod.noOfDays
              )
            )
          )
        )
      )
    )

    Second: do I see a 5-layer-deep a!update()?!?!?  What is the reasoning there?  a!update handles multiple named properties inherently.

    It looks like the top one is inserting a new property called "costAdjustments" but that the subsequent 4 are all adjusting properties under the "costAdjustments" layer, so we'll combine those 4 into one:

    a!save(
      local!newEstimates2,
      
      a!forEach(
        items: local!newEstimates,
        expression: a!localVariables(
          local!currentContractPeriodIndices: wherecontains(
            fv!item.costAdjustments.contractPeriodNum,
            tointeger(local!uniqueContractPeriods.period)
          ),
          local!currentUniqueContractPeriod: index(
            local!uniqueContractPeriods,
            local!currentContractPeriodIndices,
            null
          ),
          
          if(
            a!isNullOrEmpty(local!currentContractPeriodIndices),
            fv!item,
            
            a!update(
              fv!item,
              "costAdjustments",
              
              /* the 4-layer nesting can be replaced by a single a!update: */
              a!update(
                data: fv!item.costAdjustments,
                index: {"lengthOfMonth", "periodStartDate", "periodEndDate", "LengthOfDay"},
                value: {
                  tointeger(local!currentUniqueContractPeriod.noOfMonths),
                  local!currentUniqueContractPeriod.startDate,
                  local!currentUniqueContractPeriod.endDate,
                  local!currentUniqueContractPeriod.noOfDays
                }
              )
              
              /*a!update(
                a!update(
                  a!update(
                    a!update(
                      fv!item.costAdjustments,
                      "lengthOfMonth",
                      tointeger(local!currentUniqueContractPeriod.noOfMonths)
                    ),
                    "periodStartDate",
                    local!currentUniqueContractPeriod.startDate
                  ),
                  "periodEndDate",
                  local!currentUniqueContractPeriod.endDate
                ),
                "LengthOfDay",
                local!currentUniqueContractPeriod.noOfDays
              )*/
            )
          )
        )
      )
    )

    ...essentially reducing 67 lines of code to just shy of 40 (after commented rows are removed and discounting some of the padding blank-lines i added back for increased eye comfort).

    Beyond this, it's down to the inherent shape of your data, whether or not the indexing is functioning as you expect (i can't tell since there's no sample data in place and no real context to go on).  If you want to post an all-inclusive sample (a rule where all data is declared in local variables, external rules aren't used, and data is parsed in local variable definitions instead of a!save() statements), then i can take a look at that and help figure out why something might still not be working as expected.