I've got an array with nested arrays, and I was trying to use the *search_array* function to sift through the array and give me back their keys. It hasn't been working. Here's the code:
<?php
$array = array(
'cat1' => array(1,2,3),
'cat2' => array(4,5,6),
'cat3' => array(7,8,9),
);
foreach($array as $cat){
if(is_array($cat)
echo array_search(5,$cat); //want it to return 'cat2'
else
echo array_search(5,$array);
}
Thanks!
If you always have a two-dimensional array, then it is as easy as:
function find($needle, $haystack) {
foreach($haystack as $key=>$value){
if(is_array($value) && array_search($needle, $value) !== false) {
return $key;
}
}
return false;
}
$cat = find(5, $array);
function mySearch($haystack, $needle, $index = null)
{
$aIt = new RecursiveArrayIterator($haystack);
$it = new RecursiveIteratorIterator($aIt);
while($it->valid())
{
if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) {
return $aIt->key();
}
$it->next();
}
return false;
}
$array = array(
'cat1' => array(1,2,3),
'cat2' => array(4,5,6),
'cat3' => array(7,8,9),
);
echo $arr_key = mySearch($array, 5);
this will give u the answer
Related
given a nested array of arbitrary depth like this:
$array = array(
1400=>
array(7300=>
array(
7301=> array(),
7302=> array(),
7305=> array(
7306=>array()
),
),
7314=>array()
),
);
how would one get the hierarchy of keys for any key.
for example:
getkeys(7305);
should return 1400,7300,7305 in that order
or
getkeys(7314);
should return 1400,7314
all array keys are unique values
Using RecursiveIteratorIterator
$array = array(
1400 => array(
7300 => array(
7301=> array(),
7302 => array(),
7305 => array(
7306=>array()
),
),
7314=>array()
),
);
function getKeys($key, $array) {
$found_path = [];
$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), RecursiveIteratorIterator::SELF_FIRST);
foreach ($ritit as $leafValue) {
$path = array();
foreach (range(0, $ritit->getDepth()) as $depth) {
$path[] = $ritit->getSubIterator($depth)->key();
}
if (end($path) == $key) {
$found_path = $path;
break;
}
}
return $found_path;
}
print_r(getKeys(7305, $array));
// Array
// (
// [0] => 1400
// [1] => 7300
// [2] => 7305
// )
This is very interesting problem you have so I tried to make a function that will echo your keys. If this is not good enough pls let me know I can improve code. Thanks.
<?php
$a = array(
1400=>
array(7300=>
array(
7301=> array(),
7302=> array(),
7305=> array(
7306=>array()
),
),
7314=>array()
),
);
$mykey = 7306;
$level = 0;
$result = array();
$resultarray = test($a,$mykey,$level,$result);
function test($array,$mykey,$level,$result){
$level++;
foreach($array as $key => $element){
if($key == $mykey){
echo 'found';
print_r($result);
exit;
} else if(is_array($element)){
$result[$level] = $key;
$result1 = test($element,$mykey,$level,$result);
}
}
}
The idea is to check current array branch, and if the needle key isn't found, then iterate current items and check their array child nodes by recursive function calls. Before each step down we push a current key to stack, and pop the stack if the function does not found a needle key in whole branch. So if the key found, the function returns true by the chain, preserving successful keys in the stack.
function branchTraversing(& $branch, & $key_stack, $needle_key) {
$found = false;
if (!array_key_exists($needle_key, $branch)) {
reset($branch);
while (!$found && (list($key, $next_branch) = each($branch))) {
if (is_array($next_branch)) {
array_push($key_stack, $key);
$found = branchTraversing($next_branch, $key_stack, $needle_key);
if (!$found) {
array_pop($key_stack);
}
}
}
} else {
array_push($key_stack, $needle_key);
$found = true;
}
return $found;
}
function getPath(& $array, $needle_key) {
$path = [];
branchTraversing($array, $path, $needle_key);
return $path;
}
$test_keys = [1400, 7300, 7302, 7306, 7314, 666];
foreach ($test_keys as $search_key) {
echo '<p>' . $search_key . ' => [ '
. implode(', ', getPath($array, $search_key)) . ' ]</p>';
}
Currently stuck trying to get the last part working, wanting to get all array keys returned where the value exists.
Test data
$testArr = array(
'id' => '249653315914',
'title' => 'testing',
'description' => 'testing',
'usernames' => array('jake', 'liam', 'john'),
'masterNames' => array('jake'),
'data' => array(
'aliases' => array(
'jake'
)
)
);
Method
recursive_search('jake', $testArr);
function recursive_search($needle, $haystack, $child = false) {
$values = array();
foreach($haystack as $key => $value) {
$current_key = $key;
if($needle === $value OR (is_array($value) && $children = recursive_search($needle, $value, true) !== false)) {
if($child) {
if($needle == $value) {
return true;
}
echo "children: $child, current_key: $current_key ";
return $current_key;
}
echo "current_key: $current_key, key: $key <br>";
$values[] = $current_key;
}
}
if(!empty($values)) {
return $values;
}
return false;
}
Output
current_key: usernames, key: usernames
current_key: masterNames, key: masterNames
children: 1, current_key: aliases current_key: data, key: data
array (size=3)
0 => string 'usernames' (length=5)
1 => string 'masterNames' (length=8)
2 => string 'data' (length=4)
Expected
array(
'usernames',
'masterNames',
'data' => array('aliases')
)
I'm losing track on the $child part I think, somewhere I should be returning something and assigning it but I think I've looked at this to long and overlooking the obvious.
Any help is awesome.
$testArr = array(
'id' => '249653315914',
'title' => 'jake',
'description' => 'testing',
'usernames' => array('jake', 'liam', 'john'),
'masterNames' => array('jake'),
'data' => array(
'aliases' => array(
'jake'
),
'aliases2' => array('level3' => array('jake'))
)
);
function recursive_search($needle, $haystack) {
$return = array();
if (is_array($haystack))
foreach($haystack as $key => $value)
{
if (is_array($value))
{
$child = recursive_search($needle, $value);
if (is_array($child) && !empty($child))
$return = array_merge($return, array($key => $child));
elseif ($child) $return[] = $key;
}
elseif ($value === $needle)
if (is_integer($key))
return true;
else
$return[] = $key;
}
elseif ($haystack === $needle)
return true;
return $return;
}
Output
Array
(
[0] => title
[1] => usernames
[2] => masterNames
[data] => Array
(
[0] => aliases
[aliases2] => Array
(
[0] => level3
)
)
)
Testing is needed, no warranty that it will work in all cases. Also, in the cases like this array('level3' => array('jake'), 'jake'), it will not go deeper to level3 and so on, as 'jake' is present in the original array. Please mention if that is not a desired behavior.
Edit by Bankzilla: To work with objects
function recursive_search($needle, $haystack) {
$return = array();
if (is_array($haystack) || is_object($haystack)) {
foreach($haystack as $key => $value) {
if (is_array($value) || is_object($value)) {
$child = recursive_search($needle, $value);
if ((is_array($child) || is_object($child)) && !empty($child)) {
$return = array_merge($return, array($key => $child));
} elseif ($child) {
$return[] = $key;
}
}
elseif ($value === $needle) {
if (is_integer($key)) {
return true;
} else {
$return[] = $key;
}
}
}
} elseif ($haystack === $needle) {
return true;
}
return $return;
}
the things I thought you did wrong was checking for if current $value is an array and doing a recursive search on it, while doing nothing with the return value of it (which should be the array either false ) , here I used a more step by step approach (well at least I thought so )
this works for a "tree with more branches"
EDIT
function recursive_search($needle, $haystack) {
$values = array();
foreach($haystack as $key => $value) {
if(is_array($value)) {
$children = $this->recursive_search($needle, $value);
if($children !== false){
if(!is_bool($children) and !empty($children)){
$key = array($key => $children);
}
$values[] = $key;
}
} else if(strcmp($needle, $value) == 0 ){
if(is_int($key))
return true;
else
$vaues[] = $key;
}
}
if(!empty($values)) {
return $values;
}
return false;
}
got rid of the "0"s in the array, thx Cheery for the hint (from his response)
So I have the following array:
$array = array(array('fruit1' => 'apple'),
array('fruit2' => 'orange'),
array('veg1' => 'tomato'),
array('veg2' => 'carrot'));
and I want to run a function like this:
array_remove_recursive($array, 'tomato');
so the output is this:
$array = array(array('fruit1' => 'apple'),
array('fruit2' => 'orange'),
array('veg2' => 'carrot')); // note: the entire array containing tomato has been removed!
Is this solvable?
This will recursively unset the matching variable at any depth and then remove the parent element only if it is empty.
function recursive_unset(array &$array, $unwanted_val) {
foreach ($array as $key => &$value) {
if (is_array($value)) {
recursive_unset($value, $unwanted_val);
if(!count($value)){
unset($array[$key]);
}
} else if($value == $unwanted_val){
unset($array[$key]);
}
}
}
Function to remove recursively many values from multidimensional array.
# Example 1
$arr1 = array_remove_recursive($arr, 'tomato');
# Example 2
$arr2 = array_remove_recursive($arr, ['tomato', 'apple']);
function array_remove_recursive($arr, $values)
{
if (!is_array($values))
$values = [$values];
foreach ($arr as $k => $v) {
if (is_array($v)) {
if ($arr2 = array_remove_recursive($v, $values))
$arr[$k] = $arr2;
else
unset($arr[$k]);
} elseif (in_array($v, $values, true))
unset($arr[$k]);
}
return $arr;
}
function array_remove_recursive($getArray,$getAssocValue)
{
$returnArray = array();
if(is_array($getArray))
{
foreach($getArray as $indAssocValue)
{
if(is_array($indAssocValue))
{
foreach($indAssocValue as $innerKey=>$innerVal)
{
if($innerVal!=$getAssocValue and $innerKey!="")
{
$returnArray[] = array("$innerKey"=>$innerVal);
}
}
}
}
}
return $returnArray;
}
$array = array(array('fruit1' => 'apple'),
array('fruit2' => 'orange'),
array('veg1' => 'tomato'),
array('veg2' => 'carrot'));
print_r($array);
echo "<br />";
$array = array_remove_recursive($array, 'tomato');
print_r($array);
hope the above code would be helpfull.
array_key_exists is not working for large multidimensional array. For ex
$arr = array(
'1' => 10,
'2' => array(
'21' => 21,
'22' => 22,
'23' => array(
'test' => 100,
'231' => 231
),
),
'3' => 30,
'4' => 40
);
array_key_exists('test',$arr) returns 'false' but it works with some simple arrays.
array_key_exists does NOT work recursive (as Matti Virkkunen already pointed out). Have a look at the PHP manual, there is the following piece of code you can use to perform a recursive search:
<?php
function array_key_exists_r($needle, $haystack)
{
$result = array_key_exists($needle, $haystack);
if ($result) return $result;
foreach ($haystack as $v) {
if (is_array($v)) {
$result = array_key_exists_r($needle, $v);
}
if ($result) return $result;
}
return $result;
}
array_key_exists doesn't work on multidimensionaml arrays. if you want to do so, you have to write your own function like this:
function array_key_exists_multi($n, $arr) {
foreach ($arr as $key=>$val) {
if ($n===$key) {
return $key;
}
if (is_array($val)) {
if(multi_array_key_exists($n, $val)) {
return $key . ":" . array_key_exists_multi($n, $val);
}
}
}
return false;
}
this returns false if the key isn't found or a string containing the "location" of the key in that array (like 2:23:test) if it's found.
$test_found = false;
array_walk_recursive($arr,
function($v, $k) use (&$test_found)
{
$test_found |= ($k == 'test');
});
This requires PHP 5.3 or later.
Here is another one, works on any dimension array
function findValByKey($arr , $keySearch){
$out = null;
if (is_array($arr)){
if (array_key_exists($keySearch, $arr)){
$out = $arr[$keySearch];
}else{
foreach ($arr as $key => $value){
if ($out = self::findValByKey($value, $keySearch)){
break;
}
}
}
}
return $out;
}
$result = array_merge($arr1,$arr2);
I want to exclude numerical values of $arr2,is there an option for this?
Edit after comment:
$arr1 = array('key' => 1);
$arr2 = array('test',1 => 'test', 'key2' => 2);
after processing I need the result to be:
array('key' => 1,'key2' => 2);
Excluding numerical keys
It seems that you want to array_filter your $arr2's keys, first:
function not_numeric( $object ) {
return !is_numeric( $object );
}
$no_numeric_keys = array_filter( array_keys( $arr2 ), not_numeric );
$no_numeric_array = array_intersect_keys( $arr2, $no_numeric_keys );
$result = array_merge( $arr1, $no_numeric_array );
I'm guessing that this would work, after using $result = array_merge($arr1,$arr2);:
foreach ($result as $key => $value) {
if (is_numeric($key)) {
unset($result[$key]);
}
}
Edit:
In as few lines as possible (1) – as requested in the new title:
foreach ($result as $key => $value) { if (is_numeric($key)) { unset($result[$key]); } }
Just loop through each array and test if keys are strings:
$output = array();
foreach($arr1 as $key => $value) {
if(is_string($key)) {
$output[$key] = $value;
}
}
foreach($arr2 as $key => $value) {
if(is_string($key)) {
$output[$key] = $value;
}
}
Edit:
Since you said elegant...
function merge_arrays_string_keys()
{
$output = array();
foreach(func_get_args() as $arr)
{
if(is_array($arr))
{
foreach($arr as $key => $value) {
if(is_string($key) {
$output[$key] = $value;
}
}
}
}
return $output;
}
elegant, huh?
$test = array('test', 1 => 'test', 'key2' => 2, 33, 3 => 33, 'foo' => 'bar');
$test_non_num = array_intersect_key(
$test,
array_flip(
array_diff(
array_keys($test),
array_filter(array_keys($test), 'is_int'))));
print_r($test_non_num); // key2=>2, foo=>bar
Use this code , it will also do the require thing.
<?php
$result = array ( 1,"pavunkumar","bks", 123 , "3" ) ;
array_walk($result,'test_print');
print_r ( $result ) ;
function test_print( $val , $key )
{
global $result;
if ( gettype ( $val ) == 'integer' )
{
unset ( $result[$key] ) ;
}
}
array_diff_ukey($m=$arr2+$arr1,$m,function($k){return is_string($k);})