Recursively remove element by value - php

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.

Related

PHP - make multidimensional array to array of strings from the arrays names

I have a multidimensional array like this:
array (
level1 => array ( level1.1,
level1.2)
level2 => array ( level2.1,
level2.2 => array( level2.2.1 => 'foo',
level2.2.2 => 'bar',
level2.2.3 => 'test')
)
)
As a result I want an array of strings like this
array ("level1/level1.1",
"level1/level1.2",
"level2/level2.1",
"level2/level2.2/level2.2.1",
"level2/level2.2/level2.2.2",
"level2/level2.2/level2.2.3")
Here is the code I tried
function displayArrayRecursively($array, string $path) : array {
if($path == "")
$result_array = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$this->displayArrayRecursively($value, $path . $key . '/');
} else {
$result_array[] = $path . $key; }
}
return $result_array;
}
Any idea how I can achieve this. I could use a reference array to populate, but I want to solve it with return values.
$array = [
'level1' => [
'level1.1',
'level1.2'
],
'level2' => [
'level2.1',
'level2.2' => [
'level2.2.1' => 'foo',
'level2.2.2' => 'bar',
'level2.2.3' => 'test'
]
]
];
function arrayParser(array $array, ?string $path=null) {
$res = [];
foreach($array as $key => $value) {
if(is_array($value)) {
$res[] = arrayParser($value, ($path ? $path.'/' : $path).$key);
}
else {
$res[] = $path.'/'.(!is_numeric($key) ? $key : $value);
}
}
return flatten($res);
}
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
$res = arrayParser($array); // result

Convert flat array with dot-delimited keys to nested array

I am trying to created nested array from flat based on its keys.
Also format of keys in original array can be changed if it will simplify task.
From :
$arr = [
'player.name' => 'Joe',
'player.lastName' => 'Snow',
'team.name' => 'Stars',
'team.picture.name' => 'Joe Snow Profile',
'team.picture.file' => 'xxx.jpg'
];
To:
$arr = [
'player' => [
'name' => 'Joe'
, 'lastName' => 'Snow'
]
,'team' => [
'name'=> 'Stars'
,'picture' => [
'name' => 'Joe Snow Profile'
, 'file' =>'xxx.jpg'
]
],
];
Here is my take on it.
It should be able to handle arbitrary depth
function unflatten($arr) {
$result = array();
foreach($arr as $key => $value) {
$keys = explode(".", $key); //potentially other separator
$lastKey = array_pop($keys);
$node = &$result;
foreach($keys as $k) {
if (!array_key_exists($k, $node))
$node[$k] = array();
$node = &$node[$k];
}
$node[$lastKey] = $value;
}
return $result;
}
Combination of iteration and recursion. Could be simplified to just iterative.
$array = [
'player.name' => 'Joe',
'player.lastName' => 'Snow',
'team.name' => 'Stars',
'team.picture.name' => 'Joe Snow Profile',
'team.picture.file' => 'xxx.jpg'
];
$newArray = array ();
foreach($array as $key=> $value) {
$temp = array ();
$keys = array_reverse (explode('.', $key));
$temp[$keys[0]] = $value;
for ($i = 1; $i < count($keys); $i++) {
$temp[$keys[$i]] = $temp;
unset ($temp [$keys [$i -1]]);
}
$newArray = array_merge_recursive($newArray,$temp);
}
var_dump($newArray );
I received this question as a test, this is my answer:
<?php
function buildArray(&$newArray, $keys, $value)
{
if (sizeof($keys) == 0) {
return $value;
} else {
$key = array_shift($keys);
if (isset($newArray[$key])) {
$value = buildArray($newArray[$key], $keys, $value);
if (is_array($value)) {
$newArray[$key] += $value;
} else {
$newArray[$key] = $value;
}
$arr = $newArray;
} else {
$arr[$key] = buildArray($newArray, $keys, $value);
}
}
return $arr;
}
$arr = [
'player.name' => 'Joe',
'player.lastName' => 'Snow',
'team.name' => 'Stars',
'team.picture.name' => 'Joe Snow Profile',
'team.picture.file' => 'xxx.jpg',
];
$newArray = [];
foreach ($arr as $key => $value) {
$explodedKey = explode(".", $key);
$temp = buildArray($newArray, $explodedKey, $value);
$newArray = array_merge($temp, $newArray);
}
print_r($newArray);
?>
You could do it like this
$newArr = [];
for ($arr as $key => $val) {
$tmp = explode ('.', $key);
if (!array_key_exists ($tmp [0], $newArray){
$newArray [$tmp [0]] = [];
}
$newArray [$tmp [0]][$tmp [1]] = $val;
}
edit:
Damn didn't saw the third level in team.
Not very generic but should work for third level ;)
$newArr = [];
for ($arr as $key => $val) {
$tmp = explode ('.', $key);
if (!array_key_exists ($tmp [0], $newArray){
$newArray [$tmp [0]] = [];
}
if (count($tmp) > 2){
if (!array_key_exists ($tmp [1], $newArray[$tmp [0]]){
$newArray [$tmp [0]][$tmp[1]] = [];
}
$newArray [$tmp [0]][$tmp [1]][$tmp [2]] = $val;
} else {
$newArray [$tmp [0]][$tmp [1]] = $val;
}
}
I think you can use something like this, for converting 2d array to nested tree. But You'll have to play with parent_id
https://github.com/denis-cto/flat-array-to-nested-tree

How can I get variable from multi dimensional array with php?

Screenshot of my array like this;
Array(
[a] => val1
[b] =>
Array(
[c]=>68
)
)
How can I get variable as;
a=val1
c=68
with php using loop?
$array = array('a' => 'val1', 'b' => array('c' => 68));
echo $array['a']; //val1
echo $array['b']['c']; //68
To just output all values of a multidimensional array:
function outputValue($array){
foreach($array as $key => $value){
if(is_array($value)){
outputValue($value);
continue;
}
echo "$key=$value" . PHP_EOL;
}
}
The same can be accomplished using array_walk_recursive():
array_walk_recursive($array, function($value, $key){echo "$key=$value" . PHP_EOL;});
Have a look at: http://us.php.net/manual/en/function.http-build-query.php
It will take an array (associative) and convert it to query string.
You use the PHP function extract()
http://php.net/manual/en/function.extract.php
Like this:
<?php
$var_array = array("color" => "blue",
"size" => "medium",
"shape" => "sphere");
extract($var_array);
echo "$color, $size, $shape\n";
?>
You would use:
foreach ($x as $k=>$v)
Where $x is your array; this will loop through each element of $x and assign $k the key and $v the value.
As an example, here's a code snippet that sets the array and displays it:
$x = array('a'=>'val1', 'b'=>'val2');
foreach ($x as $k=>$v) {
echo "$k => $v<br />";
}
If you know its maximum one array deep you could use
foreach ($myArray as $key=>$val) {
if (is_array($val) {
foreach ($val as $key2=>$val2) {
print $key2.'='.$val2;
}
} else {
print $key.'='.$val;
}
}
if it could be more, use a function
function printArray($ar) {
foreach ($myArray as $key=>$val) {
if (is_array($val) {
printArray($val)
} else {
print $key.'='.$val;
}
}
}
printArray($myArray);
If you are trying to extract the variables try:
<?php
$array = array('a' => 'val1', 'b' => array('c' => 68));
$stack = array($array);
while (count($stack) !== 0) {
foreach ($stack as $k0 => $v0) {
foreach ($v0 as $k1 => $v1) {
if (is_array($v1)) {
$stack[] = $v1;
} else {
$$k1 = $v1;
}
unset($k1, $v1);
}
unset($stack[$k0], $k0, $v0);
}
}
unset($stack);
This will create $a (val1) and $c (68) inside of the current variable scope.
You can use RecursiveIteratorIterator + RecursiveArrayIterator on ArrayIterator
Example Your Current Data
$data = array(
'a' => 'val1',
'b' => array('c'=>68)
);
Solution
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator(new ArrayIterator($data)));
echo "<pre>";
foreach ($it as $k=> $var)
{
printf("%s=%s\n",$k,$var);
}
Output
a=val1
c=68
See Live Demo PHP 5.1.0 - 5.4.9

array_key_exists is not working

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;
}

How to merge arrays but no numerical keys in fewest lines in php?

$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);})

Categories