cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Choose Language Hide Translation Bar
jconte
Level II

How to make recursive function with associative array as parameter

I'm trying to parse a nested associative array in JMP 16 (extracted from a JSON). The basic structure of the JSON is as follows:

{
"groupOp": "&", "rules": [ {"column": "col1", "op": "==", "value": 1}, {
"groupOp": "|",
"rules": [
{"column": "col2", "op": "==", "value": 2}
{"column": "col3", "op": "==", "value": 3}
]
}
}

This would allow structured storage of the nested condition "col1 == 1 & (col2 == 2 | col3 == 3)", and others of arbitrary depth.

 

I wrote a recursive function to parse this structure, using the contains function to distinguish the base case from the recursive case. However, I'm running into a stack overflow error. Upon debugging I realized that while "rule" had the correct value, "obj" stayed the same on each recursive call.

 

parseFilter = Function( {obj},
	If (obj << contains("groupOp") & obj << contains("rules"),
		str = "(";
		For Each({rule}, obj["rules"],
			show(rule);
			Concat(str, Recurse(rule) || " " || groupOp || " ");
		);
		Concat(str, ")");
		Return(str);
	, // else
		Return(":" || obj["column"] || " " || obj["op"] || " " || data );
	);
);

 Is this to do with the For Each function, having an associative array as a parameter, or something else?

3 REPLIES 3
Craige_Hales
Super User

Re: How to make recursive function with associative array as parameter

Without studying too deep, the first change you probably need is to make str be local. Change

parseFilter = Function( {obj},

to

parseFilter = Function( {obj},{str},

It looks like another parameter list, but it is actually a list of variables that are local to the function, and to each recursive call of the function.

 

Craige
jconte
Level II

Re: How to make recursive function with associative array as parameter

Thanks for the tip. Still running into the same issue though.

Craige_Hales
Super User

Re: How to make recursive function with associative array as parameter

I think this might be what you are after. Untested code follows...

json =
"\[
{
  "groupOp": "&",
  "rules": [
    {"column": "col1", "op": "==", "value": 1},
    {
      "groupOp": "|",
      "rules": [
        {"column": "col2", "op": "==", "value": 2},
        {"column": "col3", "op": "==", "value": 3}
      ]
    }
    ]
}
	
]\";

parseFilter = Function( {obj},
	{str, first},
	If( obj << Contains( "groupOp" ) & obj << Contains( "rules" ),
		str = "(";
		first = 1;
		For Each( {rule}, obj["rules"],
			If( first,
				first = 0;
			,// else
				str ||= (" " || obj["groupOp"] || " ")
			);
			str ||= Recurse( rule );
		);
		str ||= ")";
		Return( str );
	, // else
		Return( ":" || obj["column"] || " " || obj["op"] || " " || Char( obj["value"] ) )
	)
);

Write( parsefilter( Parse JSON( json ) ) );

(:col1 == 1 & (:col2 == 2 | :col3 == 3))

 

 

Craige