Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Filter Associative Multidimensional Array

Status
Not open for further replies.

NigeW

Programmer
Jun 10, 2002
134
NZ
I have an array that is a complete list of "pages" for a CMS I have written.

I am wanting to filter the array in order to output a sub navigation for my site.

I felt that the filter_var_array() function would be suitable as it provides the ability to search on multiple criteria, however I cannot see that it works on multidimensional arrays.

A snippet of my code is below - what I am wanting to filter on is the parent and the hidden array variables:
Code:
Array
(
    [Home] => Array
        (
            [id] => 2
            [type] => content
            [name] => Home
            [url] => Home
            [parentID] => 1
            [parentName] => Site
            [parentURLName] => Site
            [listorder] => 1
            [contentid] => 1
            [hidden] => 0
            [title] => CMS
            [metadescription] => CMS
            [template] => public/templates/ug_template.html
            [metakeywords] => CMS
        )
Any suggestions ?

Thanks

Nigel
 
so what do you want the output, or filtered array, to look like?
 
Well, in previous posts, we have established that my understanding and practice of PHP code is questionable. But since I once had the same question as you, NigeW, I will share my recursive solution with you

Code:
function arraySearch($strNeedle, $arrHaystack, $strKey = false)
{
	$boolFound = false;
	if ($arrHaystack == $strNeedle)
		return true;
	
	if (is_array($arrHaystack))
	{
		if ($strKey != false)
			if ($arrHaystack[$strKey] == $strNeedle)
				return true;
		
		foreach($arrHaystack as $key => $objTemp)
		{
			
			if (is_array($objTemp))
			{
				$boolFound = arraySearch($strNeedle, $objTemp, $strKey);
			}
			else
			{
				if (strtolower($objTemp) == strtolower($strNeedle))
					return $key;
			}
		}
	}
	else
		return false;

	return $boolFound;
}

$strNeedle = what value are you searching for
$arrHaystack = the array (any dimension) to be searched.
$strKey = if the $strNeedle is found, the key must equal $strKey for the find to be valid.


Using your print_r "arrHome":

arrSearch (arrHome, "CMS") 'return true
arrSearch (arrHome, "CMS", "template") 'returns false
arrSearch (arrHome, "CMS", "metadescription") 'returns true.

-Geates
 
Hi jpadie

Here is the desired using the original code snippet is below:

Code:
Array
(
    [Home] => Array
        (
            [name] => Home
            [parentURLName] => Site
        )

So what I intended doing was creating a self referencing function using a temporary array to build an unordered list (with nested lists) of links.

I have tried using array_filter() with the callback function but I need to pass in a third variable which the function doesn't provide for - I guess I could set a session variable to get around this problem, but thought filter_var_array() looked a promising option.

Geates - thanks for your feedback. I will hold off using your code at this stage in the hope I can use filter_var_array().

Thanks to you both for your responses.

Nigel Wilson
Christchurch Web Design
 
I don't blame you. I mis-interpreted what you were asking. From what I gather, you want to extract certain parts of an array and return the results as an array. Am I on the right path.

-Geates
 
Hi Geates

Bang on - a filtered array from the parent array.

My parent array has in excess of 200 sub arrays so was looking for the most efficient way to perform the filter. Maybe I'll just resort to some good old looping.

Thanks again

Nigel

Nigel Wilson
Yoyo CMS
 
manipulating arrays is very straightforward. but to show you the optimum solution you need to explain (with precision) what shape you want from the filter.
 
I agree. Let's say you are looking for the key 'name' with a value of 'Home'. If found, which do you want return?

full array traversal:
Code:
array(
   [root] => array(
      [parent] => array(
         [child] => array(
            [name] => Home
         )
      )
   )
)

or just the child array:
Code:
array(
   [child] => array(
       [name] => Home
   )
)

Or am I misinterpreting your request.

-Geates
 
OK . . . in trying to keep things brief, it is obvious when re-reading my posts that I am not providing sufficient details - why can't people just read my mind! lol

So I hope this helps . . .

Starting with an array :

Code:
Array
(
    [Home] => Array
        (
            [id] => 2
            [type] => content
            [name] => Home
            [url] => Home
            [parentID] => 1
            [parentName] => Site
            [parentURLName] => Site
            [listorder] => 1
            [contentid] => 1
            [hidden] => 0
            [title] => CMS
            [metadescription] => CMS
            [template] => public/templates/ug_template.html
            [metakeywords] => CMS
        )
...

I want to filter on "parentURLName" and "hidden" within each sub array and return for following for each match :

Code:
Array
(
    [Home] => Array
        (
            [name] => Home
            [parentURLName] => Site
        )
...

So there is no manipulation required, merely filtering.

Thanks for your patience and if you have any suggestions I'd be very grateful.

Nigel Wilson
Yoyo CMS
 
Code:
$output = array();
foreach ($array as $key=>$a){
  if ($a['hidden'] == 'somevalue'){
  $output[$key] = array('name'=>$a['name'], 'parentURLName'=>$a['parentURLName']);
  }
}

your code does not show how you filter on 'hidden'. however the above should help a little bit.
 
Hi jpadie

Thanks for the code.

I have implemented a modified version of the code you supplied and it is working fine.

Obviously I was hoping that the filter_var_array() function could work on multi-dimensional associative arrays.

Thanks to you and Geates for your time / suggestions.

Nigel Wilson
Yoyo CMS
 
i don't think that the array filter functions exist for the purpose of validating content against values. but more against value types. i must admit not to having checked the source code to see how they actually work. the documentation is rather poor. perhaps this link may help.
 
After I read jpadie's solution I realized that the scope of your request was much smaller than I thought. However, I wanted finish the solution that I started. My function is called arrayFilter($arrHaystack, $arrFilter, $boolStrict).

$arrHaystack = the assoc. array to be filtered
$arrFilter = an assoc. array containing key=>value filters
$boolStrict = true - the parent object in which ALL filters are valid is returned. false - the parent object in which ANY of the filters are valid is returned.

Code:
function arrayFilter($arrHaystack, $arrFilter, $boolStrict = false)
{
	if (!is_array($arrFilter)) $arrFilter = array($arrFilter);
	if (!is_array($arrHaystack)) $arrHaystack = array($arrHaystack);

	foreach ($arrHaystack as $strHKey => $objHValue)
	{
		if (is_array($objHValue))
			$boolFound = arrayFilter($objHValue, $arrFilter, $boolStrict);
		else
		{
			$strHKey = strtolower($strHKey);
			$objHValue = strtolower($objHValue);
			foreach ($arrFilter as $strFKey => $objFValue)
			{
				$strFKey = strtolower($strFKey);
				$objFValue = strtolower($objFValue);
								
				$boolMatch = (($strFKey == $strHKey) AND ($objFValue == $objHValue));
			
				if ($boolMatch == 1)
					if ($boolStrict)
						unset($arrFilter[$strFKey]);
					else
						$arrFilter = array();
						
				if (count($arrFilter) == 0)
					return true;
			}
		}
		
		if ($boolFound)
			$arrResult[$strHKey] = $objHValue;
	}

	return $arrResult;	
}
With it, you can case-insensatively filter an array down to objects that contain the condition(s) of your filter. That's right, you can filter an array with an array of filters...

Given:

Code:
$arrHomes = array(
	"Wendy" => array(
		"color" => "White",
		"stories" => array(
			"basement" => true,
			"floors" => 2),
		"style" => "Colonial"),
	"Bill" => array(
		"color" => "Red",
		"stories" => 1,
		"style" => "Bungelow"),
	"Karen" => array(
		"color" => "Blue",
		"stories" => array(
			"basement" => false,
			"floors" => 3),
		"style" => "Tudor"),
	"Mike" => array(
		"color" => "Blue",
		"stories" => array(
			"basement" => false,
			"floors" => 4),
		"style" => "Palace"),
	"Sarah" => array(
		"stories" => array(
			"basement" => true,
			"floors" => 4),
		"style" => "Castle")
);

I can extract objects containing my filters:

Code:
//Example 1: single strict filter
$arrFilter = array("color" => "blue");
print_r(arrayFilter($arrHomes, $arrFilter, true));

//Output
array(
	"Karen" => array(
		"color" => "Blue",
		"stories" => array(
			"basement" => false,
			"floors" => 3),
		"style" => "Tudor"),
	"Mike" => array(
		"color" => "Blue",
		"stories" => array(
			"basement" => false,
			"floors" => 4),
		"style" => "Palace")
)

//Example 2: multiple strict filters
$arrFilter = array("color" => "blue", "floors" => "4");
print_r(arrayFilter($arrHomes, $arrFilter, true));

//Output
array(
	"Mike" => array(
		"color" => "Blue",
		"stories" => array(
			"basement" => false,
			"floors" => 4),
		"style" => "Palace")
)

//Example 3: multiple loose filters
$arrFilter = array("color" => "blue", "floors" => "4");
print_r(arrayFilter($arrHomes, $arrFilter, false));

//Output
array(
	"Mike" => array(
		"color" => "Blue",
		"stories" => array(
			"basement" => false,
			"floors" => 4),
		"style" => "Palace"),
	"Karen" => array(
		"color" => "Blue",
		"stories" => array(
			"basement" => false,
			"floors" => 3),
		"style" => "Tudor"),
	"Sarah" => array(
		"stories" => array(
			"basement" => true,
			"floors" => 4),
		"style" => "Castle")
)

How does this help you? Because to obtain your goal, all you need is:

Code:
$arrFilters = array("hidden" => "somevalue");
arrFilter($arrMyArray, $arrFilters, true);

As I was coding this function, I realized how EASY this task would be with MySQL. I suppose arrayFilter is a primative SELECT for multi-dim assoc. arrays.

-Geates

jpadie - It seems like this code may produce excessive overhead. Is this the right approach?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top