I am trying to create an object to satisfy the structure required by json-logic-js. An example of that structure is provided below.
The source array is made up of booleans
and strings
. Strings can only be OR
, AND
, NAND
or NOR
. For now am I working only with OR
and AND
.
The array of booleans and strings might look like the below. The values are dynamic. So the booleans can be either true or false and strings as mentioned above.
const source = [false, "OR", false, "OR", false, "AND", false, "AND", false, "OR", true]
The grouping of this source array if it were in an if statement would I believe be as follows:
(false || false || (false && false && false) || true) // true
And I would expect to output the following object which satifies the json-logic-js JS package:
const result = {
'or': [
false,
false,
{
'and': [
false,
false,
false,
]
},
true,
]
}
I have tried recursive functions and have been playing with the .reduce() method but as have yet been unable to find a solution. I struggle creating the object as I iterate over the source array. I have searched for similar answers here on SO but none seem to want the same result object structure as I do.
CodePudding user response:
Try the following solution. Hopefully the code is more or less self-explanatory:
function process(arr) {
const isBool = (x) => x === true || x === false;
const prec = (x) => -["AND", "OR"].indexOf(x);
// Convert infix -> postfix
const postfix = [];
const ops = [];
for (const x of arr) {
if (!isBool(x)) {
const prev = ops[ops.length - 1];
if (prev === undefined || prec(x) > prec(prev)) {
ops.push(x);
} else {
while (ops.length > 0 && prec(x) < prec(ops[ops.length - 1])) {
postfix.push(ops.pop());
}
ops.push(x);
}
} else {
postfix.push(x);
}
}
postfix.push(...ops.reverse());
// Convert postfix -> output format
const stack = [];
for (const x of postfix) {
if (!isBool(x)) {
const op = x.toLowerCase();
const prevs = [stack.pop(), stack.pop()];
const obj = prevs.find((y) => !isBool(y) && y.hasOwnProperty(op));
if (obj !== undefined) {
const other = prevs.find((y) => y !== obj);
obj[op].push(other);
stack.push(obj);
} else {
stack.push({
[op]: prevs,
});
}
} else {
stack.push(x);
}
}
return stack[0];
}
console.log(JSON.stringify(process([false, "OR", false, "OR", false, "AND", false, "AND", false, "OR", true]), null, 2));