json-logic-js icon indicating copy to clipboard operation
json-logic-js copied to clipboard

Change the reduce function to evaluate the initial value

Open ubik2 opened this issue 1 year ago • 0 comments

Change the reduce function to evaluate the initial value, which lets us capture state for use in the logic function.

Normally, when we iterate through elements in a reduce function, we only have access to that one element. We aren't able to capture any state from outside.

For example, if I have a list of elements, and want to know which are more than 2, I can do the following:

jsonLogic.apply({
  "reduce": [
    [1, 2, 3, 4, 5],
    { "+": [{ "if": [{ ">": [{ "var": "current" }, 2] }, 1, 0] }, { "var": "accumulator" }] },
    0
  ]
}); // 3

However, if I want to be able to set the threshold of 2 based on data, I am unable to access that within the reduce.

Reworking this, so that I can pass both the initial count and the goal in the accumulator by having the initial value be an array with the count and the threshold, I can do:

jsonLogic.apply({
  "reduce": [
    [1, 2, 3, 4, 5],
    [
      { "+": [{ "if": [{ ">": [{ "var": "current" }, { "var": "accumulator.1" }] }, 1, 0] }, { "var": "accumulator.0" }] },
      { "var": "accumulator.1" }
    ],
    [0, 2]
  ]
}); // [3, 2]

If I want to provide the threshold in the data portion, things don't work as expected, since the initial value is not applied.

jsonLogic.apply({
  "reduce": [
    [1, 2, 3, 4, 5],
    [
      { "+": [{ "if": [{ ">": [{ "var": "current" }, { "var": "accumulator.1" }] }, 1, 0] }, { "var": "accumulator.0" }] },
      { "var": "accumulator.1" }
    ],
    [0, {"var": "threshold"}]
  ]
}, {"threshold": 2}); // [0, {var: "threshold"}]

With this change, the initial value will be evaluated, so we get the expected answer of [3, 2].

ubik2 avatar Nov 23 '22 10:11 ubik2