How to reference a previous iteration in forEach in subsequent iterations

Certified Senior Developer

My use case is as follows:

I have a CDT of dates and number of days.  I have the first date, but the others are not populated yet.  My goal is to populate each subsequent date with the previous indexes date + the number of days of the current iteration.

For example I start with the following:

{9/27/2021, 0}, {null,3}, {null,5}

I want the output to be as follows:

{9/27/2021, 0}, {9/30/2021,3}, {10/5/2021,5}

Each iteration will reference the previous iteration's date to generate its own date.

I appreciate your time and help!

  Discussion posts and replies are publicly visible

Parents
  • 0
    Certified Lead Developer

    This sort of case is tougher to handle even in a!forEach() implementations (don't get me started on the horrible older looping functions it replaced).  The issue is that we have to assume every loop of the rule evaluate simultaneously - meaning in evaluation X, we don't have access to the result of evaluation X - 1.  We can, however, look at the original value of X - 1 (i.e. "local!myArray[fv!index - 1]"), which only helps us partially in your case.

    So to handle item 2 in your array it's fairly easy -- something like resultDate: local!myArray[fv!index - 1] + fv!item.days

    The issue is, for item 3 in your array, it'll look back at the original value of item 2 (with a blank date) and that won't be much help.  I think the solution here would be to build a sub-loop inside the primary loop, which looks back to the beginning of the list and finds the first non-null date (and of course it would need to track all the differential "days" values in between, to further complicate matters).  If I have time later I might try circling back to this to see if I can help with a working example, unless someone beats me to it, but I don't know it off the top of my head (and i can't 100% guarantee it's possible, though I suspect it is).  It may be the sort of thing that gets far easier if you write a recursive helper rule, though that always gets tricky to implement and test.

  • 0
    Certified Lead Developer
    in reply to Mike Schmitt

    Edit: bad implementation!

    ...could be an interesting code golf challenge!

  • 0
    Certified Lead Developer
    in reply to Josh

    Nice - though this code seems to give a "date" value in the final iteration of 5 days after the initial date, instead of 5 days after (3 days after) the initial date.

  • +1
    Certified Lead Developer
    in reply to Josh

    This modification (with an internal reverse-loop to calculate accurate running days) seems to work though:

    a!localvariables(
      local!sampleData: {
        a!map(date: date(2021, 9, 27), diff: 0),
        a!map(date: null, diff: 3), 
        a!map(date: null, diff: 5)
      },
      /*local!runningDifference: 0,*/
      
      a!forEach(
        items: local!sampleData,
        expression: if(
          /*fv!index = 1,*/fv!isFirst,
          fv!item,
          
          a!localVariables(
            local!runningDifference: sum(
              a!forEach(
                reverse(enumerate(fv!index)+1),
                local!sampleData[fv!item].diff
              )
            ),
            a!map(
              date: local!sampleData[1].date + local!runningDifference,
              diff: fv!item.diff
            )
          )
        )
      )
    )

  • 0
    Certified Lead Developer
    in reply to Mike Schmitt

    Yeah you are right, I thought the running difference would keep track of changes outside of the inner local var because it is declared outside, but I guess it is not being scoped correctly.

  • 0
    Certified Lead Developer
    in reply to Josh

    Yeah, that's the real rub of not being able to push a new value into a variable in static code...

  • +1
    Certified Lead Developer
    in reply to Mike Schmitt

    Your enumerate usage inspired this: 

    a!localvariables(
      local!sampleData: {
        a!map(date: date(2021, 9, 27), diff: 0),
        a!map(date: null, diff: 3), 
        a!map(date: null, diff: 5)
      },
      a!forEach(
        items: local!sampleData,
        expression: if(fv!isFirst,
          fv!item,
          a!map(
            date: local!sampleData[1].date + sum(index(local!sampleData.diff, 1 + enumerate(fv!index))), 
            diff: fv!item.diff
          )
        )
      )
    )

Reply
  • +1
    Certified Lead Developer
    in reply to Mike Schmitt

    Your enumerate usage inspired this: 

    a!localvariables(
      local!sampleData: {
        a!map(date: date(2021, 9, 27), diff: 0),
        a!map(date: null, diff: 3), 
        a!map(date: null, diff: 5)
      },
      a!forEach(
        items: local!sampleData,
        expression: if(fv!isFirst,
          fv!item,
          a!map(
            date: local!sampleData[1].date + sum(index(local!sampleData.diff, 1 + enumerate(fv!index))), 
            diff: fv!item.diff
          )
        )
      )
    )

Children
No Data