Jump to content

collapsing a 3 level array into a string to set as option value


Greywacke
 Share

Recommended Posts

hi all,struggling slightly to wrap my head around this. sofar i've got the method, which would be as follows:

	for (i = 0; i < arr.length; i++) {		if (arr[i] instanceof Array) {			arr[i] = arr[i].join(";;;");		}	}	var val = arr.join(";;");

now i understand that this is 2 levels of arrays and i need to collapse 3, some elements not being arrays.the array passed as arr, is somewhat as follows - the new lines and groups of new lines denote a level 1 element.|- denotes the start of a subarray, |_ denotes the end of a subarray.the groups are level 2 and the groups within the groups are at level 3.eg.

11Category A20|-	351|	budget|	disabled|	|-	527|	|_	10,000|	|-	397|	|	10,000|_	|_	1

the 3rd level arrays with 3 number/string elements are for a selected attribute value and it's properties, the third property is the combination of attributes they belong to.the 3rd level arrays with 2 number/string elements are for an available attribute value and it's properties.the 2nd level number/string elements that are not an array are the attribute key properties, and the 1st level number/string elements are properties of the category. an example of the xml looks as follows:

	<pricecat>		<catid>1</catid>		<svcid>1</svcid>		<catdesc>Category A</catdesc>		<catprice>20</catprice>		<catgroup id="531" desc="Budget" disabled="disabled">			<availattrval id="527" value="R10,000 to R12,500" />			<availattrval id="526" value="R12,500 plus" />			<availattrval id="531" value="R3,000 to R4,000" />			<availattrval id="530" value="R4,000 to R5,000" />			<availattrval id="529" value="R5,000 to R7,500" />			<availattrval id="528" value="R7,500 to R10,000" />		</catgroup>		<catgroup id="525" desc="Fitment" disabled="disabled">			<availattrval id="520" value="ASAP" />			<availattrval id="525" value="Not within the next 3 months" />			<availattrval id="523" value="Within the next 2 months" />			<availattrval id="521" value="Within the next 2 weeks" />			<availattrval id="524" value="Within the next 3 months" />			<availattrval id="522" value="Within the next month" />		</catgroup>		<catgroup id="286" desc="Requirement" disabled="disabled">			<availattrval id="289" value="New - Colour-coded" />			<availattrval id="288" value="New - White" />			<availattrval id="287" value="Pre-owned - Colour-coded" />			<availattrval id="286" value="Pre-owned - White" />		</catgroup>		<catgroup id="393" desc="budget" disabled="disabled">			<availattrval id="397" value="R10,000 to R12,500" />			<availattrval id="398" value="R12,500 plus" />			<availattrval id="393" value="R3,000 to R4,000" />			<availattrval id="394" value="R4,000 to R5,000" />			<availattrval id="395" value="R5,000 to R7,500" />			<availattrval id="396" value="R7,500 to R10,000" />			<validattrval id="397" value="R10,000 to R12,500" combo="1" />		</catgroup>		<catgroup id="1" desc="canopy_req" disabled="disabled">			<availattrval id="2" value="new_colour_coded" />			<availattrval id="1" value="new_white" />			<availattrval id="12" value="pre-owned_colour_coded" />			<availattrval id="11" value="pre-owned_white" />			<validattrval id="1" value="new_white" combo="1" />		</catgroup>		<catgroup id="519" desc="fitment" disabled="disabled">			<availattrval id="514" value="ASAP" />			<availattrval id="519" value="not_within_3_months" />			<availattrval id="517" value="within_2_months" />			<availattrval id="515" value="within_2_weeks" />			<availattrval id="518" value="within_3_months" />			<availattrval id="516" value="within_month" />		</catgroup>	</pricecat>

they are successfully retrieved into a 3 level array as the example in the second codebox.i am struggling to wrap my head around parsing this array though... could somebody give me some assistance/advice (even if it's "not what i want to hear") please?

Edited by Pierre 'Greywacke' du Toit
Link to comment
Share on other sites

i guess this can be done as follows:

	for (var i = 0; i < arr.length; i++) {		if (arr[i] instanceof Array) {			for (var j = 0; j < arr[i].length; j++) {				if (arr[i][j] instanceof Array) {					arr[i][j] = rr[i][j].join(";;");				}			}			arr[i] = arr[i].join(";;;");		}	}	var val = arr.join(";;;;");

but i am wondering now... could a generic function be written to do this, and if so how would one collapse a multidimentional javascript array of any depth down to a string, retaining all the values and the scope? i.e. possibly loop each dimention level it goes into untill no more dimention levels... :)unfortunately i can't seem to find anything available on the net regarding this specifically, except for a PHP function that apparently does something like this for JSON (json_convert, but the source code is not available to inspect...).just performing a join on the root array of a multidimentional array does not retain the subarray values, unfortunately...

Edited by Pierre 'Greywacke' du Toit
Link to comment
Share on other sites

The toString() method will collapse an array into a comma delimited string. It displays all the values of child arrays as well. However, there's no way to tell what values belong to which child arrays.Ex.var arrTest = new Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9));var arrString = arrTest.toString();arrString will equal:1,2,3,4,5,6,7,8,9FWIW, there is also the toSource() method which will print out the source code (JSON syntax) of an object/array. Unfortunately it only works in FF. :)

Link to comment
Share on other sites

well unfortunately i cannot store them as comma delimited, because some attributes (especially the budgets) have comma's in them. also, i need to restore the multidimentional array at a later stage to parse and insert into the form elements...

Link to comment
Share on other sites

Perhaps this might help. This is PHP, but you might be able to derive something from it. It's a custom JSON encoder function that I wrote.

function js_encode($arrVariable, $useObjNames=false) {	/* With the help of php.net and user contributed notes on JSON encoding (found on php.net)	Special thanks to the user andyrusterholz, whose code I used as a basis	I was able to write this function to encode PHP arrays into JSON syntax for use in JavaScript		This function only handles arrays, but it can handle pretty much any kind of array you can throw	at it.  If useObjNames is true, this function appends a 'Key_' prefix to numeric keys since a javascript	object cannot have properties with names that begin with numbers.  The function also replaces any 	characters that would make illegal property names (such as '-' or '&') with textual representations	of those characters	*/	$strResult = '';		if (!is_array($arrVariable)) { //If the variable is not an array, return false		$strResult = false;	} else { //If the variable is an array, encode it		$arrKeys = array_keys($arrVariable);		$arrK_Keys = array_keys(array_keys($arrVariable));		$arrDiff = array_diff($arrKeys, $arrK_Keys);				$keyDiff = count($arrDiff);		if ($keyDiff > 0) { //Associative array (array with specified keys, ex. array("one" => 1, "two" => 2) )			$strResult = '{';						foreach ($arrVariable as $key => $value) {				if (is_array($value)) {					$value = js_encode($value);				} elseif (!is_numeric($value) || is_string($value)) { //if the value is not a number, put quotes around it					$value = "\"".addslashes($value)."\"";				}								if ($useObjNames) {					if (is_numeric($key) || is_numeric(substr($key, 0, 1))) {						//If the key or the first character of the key is a number, add prefix 'Key_' to it so that it is a valid object property name						$key = "Key_".$key;					}										//Replace any illegal characters with textual representations					$arrChars = getIllegalJSON();					$arrFind = $arrChars['Chars'];					$arrRplc = $arrChars['Text'];										$key = addslashes(str_replace($arrFind, $arrRplc, $key));				}								if ($strResult != '{') {					$strResult.=", \"".$key."\": ".$value;				} else {					$strResult.="\"".$key."\": ".$value;				}			}			$strResult.='}';		} else { //Vector array (standard array without specified keys, ex. array(1, 2, 3) )			$strResult = '[';						foreach ($arrVariable as $value) {				if (is_array($value)) {					$value = js_encode($value);				} elseif (!is_numeric($value)) { //if the value is not a number, put quotes around it					$value = "'".addslashes($value)."'";				}								if ($strResult != '[') {					$strResult.=", ".$value;				} else {					$strResult.=$value;				}			}			$strResult.=']';		}	}		return $strResult;}//This function returns the characters that are replaced in the js_encode() functionfunction getIllegalJSON() {	$arrChars = array();		$arrChars['Chars'] = array('.', ',', '=', '+', '-', '*', '/', '!', '@', '#', '$', '%', '^', '&');	$arrChars['Text'] = array('_', '_', '_eqls_', '_plus_', '_minus_', '_mult_', '_div_', '_excl_', '_at_', '_num_', '_dllr_', '_prcnt_', '_pow_', '_and_');		return $arrChars;}

It works really well for what I use it for, hopefully it can help you. :)

Link to comment
Share on other sites

i've redone the xml last night - i see the categories are a four dimentional array - and the services a 3 dimentional array, here is a view of the data retrieved into a multidimentional array (there will eventually be more than one category):

A Category arrayArray {	1,	1,	"Category A",	20,	Array {		531,		"Budget",		"disabled"	},	Array {		525,		"Fitment",		"disabled"	},	Array {		286,		"Requirement",		"disabled"	},	Array {		393,		"budget",		"disabled",		Array {			397,	 		"R10,000 to R12,500",			1		}	},	Array {		1,		"canopy_req",		"disabled",		Array {			1,			"new_white",			1		}	},	Array {		519,		"fitment",		"disabled"	}}Services ArrayArray {	1,	"Bakkie Canopy",	"selected"	Array {		531,		"Budget",		"disabled",		Array {			527,			"R10,000 to R12,500"		},		Array {			526,			"R12,500 plus"		},		Array {			531,			"R3,000 to R4,000"		},		Array {			530,			"R4,000 to R5,000"		},		Array {			529,			"R5,000 to R7,500"		},		Array {			528,			"R7,500 to R10,000"		}	},	Array {		525,		"Fitment",		"disabled",		Array {			520,			"ASAP"		},		Array {			525,			"Not within the next 3 months"		},		Array {			523,			"Within the next 2 months"		},		Array {			521,			"Within the next 2 weeks"		},		Array {			524,			"Within the next 3 months"		},		Array {			522,			"Within the next month"		}	},	Array {		286,		"Requirement",		"disabled",,		Array {			289,			"New - Colour-coded"		},		Array {			288,			"New - White"		},		Array {			287,			"Pre-owned - Colour-coded"		},		Array {			286,			"Pre-owned - White"		}	},	Array {		393,		"budget",		"disabled",,		Array {			527,			"R10,000 to R12,500"		},		Array {			526,			"R12,500 plus"		},		Array {			531,			"R3,000 to R4,000"		},		Array {			530,			"R4,000 to R5,000"		},		Array {			529,			"R7,500 to R10,000"		}	},	Array {		1,		"canopy_req",		"disabled",		Array {			2,			"new_colour_coded"		},		Array {			1,			"new_white"		},		Array {			12,			"pre-owned_colour_coded"		},		Array {			11,			"pre-owned_white"		}	},	Array {		519,		"fitment",		"disabled",		Array {			514,			"ASAP"		},		Array {			519,			"not_within_3_months"		},		Array {			517,			"within_2_months"		},		Array {			515,			"within_2_weeks"		},		Array {			518,			"within_3_months"		},		Array {			512,			"within_month"		}	}}

these are the functions that collapse and expand this multidimentional array. i am thinking that perhaps the levels need to be added as parameter to specify how deep to parse. i'm as yet still on this one.

function collapse(arr) {	for (var i = 0; i < arr.length; i++) {		if (arr[i] instanceof Array) {			for (var j = 0; j < arr[i].length; j++) {				if (arr[i][j] instanceof Array) {					arr[i][j] = arr[i][j].join(";;");				}			}			arr[i] = arr[i].join(";;;");		}	}	return arr.join(";;;;");;	}function expand(str) {	var arr = str.split(";;;;");	for (var i = 0; i < arr.length; i++) {		if (arr[i].indexOf(";;;")) {			arr[i] = arr[i].split(";;;");			for (var j = 0; j < arr[i].length; j++) {				if (arr[i][j].indexOf(";;")) {					arr[i][j] = arr[i][j].split(";;");				}			}		}	}	return arr;}

Edited by Pierre 'Greywacke' du Toit
Link to comment
Share on other sites

Definitely look into using JSON for this, it's probably the best way to go. You don't need to mess around with delimiters and it will always retain the exact same structure. I use JSON data for all communication between my ajax applications and PHP, both directions.

Link to comment
Share on other sites

had a look at using JSON, but i believe it would be better for a solution if i simplify the xml even more - as follows:

<?xml version="1.0" encoding="UTF-8" ?><root>	<pricecat>		<catid>1</catid>		<svcid>1</svcid>		<catdesc>Category A</catdesc>		<catprice>20</catprice>		<validattrval combo="1" avid="397" ak="budget" av="R10,000 to R12,500" />		<validattrval combo="1" avid="1" ak="canopy_req" av="new_white" />	</pricecat>	<services>		<service id="1" name="Bakkie Canopy" selected="selected">		<select id="531" key="Budget" option527="527;.;R10,000 to R12,500" option526="526;.;R12,500 plus" option531="531;.;R3,000 to R4,000" option530="530;.;R4,000 to R5,000" option529="529;.;R5,000 to R7,500" option528="528;.;R7,500 to R10,000" />		<select id="525" key="Fitment" option520="520;.;ASAP" option525="525;.;Not within the next 3 months" option523="523;.;Within the next 2 months" option521="521;.;Within the next 2 weeks" option524="524;.;Within the next 3 months" option522="522;.;Within the next month" />		<select id="286" key="Requirement" option289="289;.;New - Colour-coded" option288="288;.;New - White" option287="287;.;Pre-owned - Colour-coded" option286="286;.;Pre-owned - White" />		<select id="393" key="budget" option397="397;.;R10,000 to R12,500" option398="398;.;R12,500 plus" option393="393;.;R3,000 to R4,000" option394="394;.;R4,000 to R5,000" option395="395;.;R5,000 to R7,500" option396="396;.;R7,500 to R10,000" />		<select id="1" key="canopy_req" option2="2;.;new_colour_coded" option1="1;.;new_white" option12="12;.;pre-owned_colour_coded" option11="11;.;pre-owned_white" />		<select id="519" key="fitment" option514="514;.;ASAP" option519="519;.;not_within_3_months" option517="517;.;within_2_months" option515="515;.;within_2_weeks" option518="518;.;within_3_months" option516="516;.;within_month" />		</service>	</services>	<sql></sql></root>

easier to keep track of while parsing :)

Link to comment
Share on other sites

this seems to work way better :) issue resolved! :)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...