What's the best way to remove the parent of a matched key in an Multidimensional Array? For example, let's assume we have the following array and I want to find "[text] = a" and then delete its parent array [0]...
(array) Array
(
[0] => Array
(
[text] => a
[height] => 30
)
[1] => Array
(
[text] => k
[height] => 30
)
)
Here’s the obvious:
foreach ($array as $key => $item) {
if ($item['text'] === 'a') {
unset($array[$key]);
}
}
using array_filter:
function filter_callback($v) {
return !isset($v['text']) || $v['text'] !== 'a';
}
$array = array_filter($array, 'filter_callback');
this will only leave 'parent elements' in the array where text != a, therefore deleting those where text equals a
The inner arrays don't maintain any reference to their "parent" arrays, so you'd have to write a function to manually track this. Something like this might work:
function searchAndDestroy(&$arr, $needle) {
foreach ($arr as &$item) {
if (is_array($item)) {
if (searchAndDestroy($item, $needle)) {
return true;
}
} else if ($item === $needle) {
$item = null;
return true;
}
}
}
Note that this is designed to work at any level of nesting, not just two dimensions, so it might be a bit of overkill if you only need it for situations like in your example.
A simple and safe solution(I'd not remove/unset elements from an array I'm looping through) could be:
$new_array = array();
foreach($array as $item)
{
if($item['text'] != "a")
{
$new_array[] = $item;
}
}
My implementation:
function searchAndDestroy(&$a, $key, $val){
foreach($a as $k => &$v){
if(is_array($v)){
$r = searchAndDestroy(&$v, $key, $val);
if($r){
unset($a[$k]);
}
}elseif($key == $k && $val == $v){
return true;
}
}
return false;
}
searchAndDestroy($arr, 'text', 'a');
To test it:
<pre><?php
function searchAndDestroy(&$a, $key, $val){
foreach($a as $k => &$v){
if(is_array($v)){
$r = searchAndDestroy(&$v, $key, $val);
if($r){
unset($a[$k]);
}
}elseif($key == $k && $val == $v){
return true;
}
}
return false;
}
$arr = array(array('text'=>'a','height'=>'30'),array('text'=>'k','height'=>array('text'=>'a','height'=>'20')));
var_dump($arr);
searchAndDestroy($arr, 'text', 'a');
var_dump($arr);
?></pre>
This function does it recursively.
Related
This question already has answers here:
PHP - Check if two arrays are equal
(19 answers)
Closed last year.
The two arrays are considered equal since they have the same 1st dimension indexes (Electric, Gas, Water) the same 2nd dimension indexes (Gym, Library), and the same values for each intersect. The second level values will always be scalar (not arrays or objects). Order doesn't matter.
How can PHP verify that they are equal based on the above definition of equality?
$array1 = [
'Electric' => ['Gym' => 24, 'Library' => 25],
'Gas' => ['Gym' => 13, 'Library' => null],
'Water' => ['Gym' => null, 'Library' => null]
];
$array2 = [
'Gas' => ['Library' => null, 'Gym' => 13],
'Electric' => ['Gym' => 24, 'Library' => 25],
'Water' => ['Library' => null, 'Gym' => null]
];
My attempt is as follows...
if (count($arr1) != count($arr2) || array_diff($arr1, $arr2) !== array_diff($arr2, $arr1)) {
$error = 'Values do not match.';
}
Here's a recursive comparison function
function CompareRecursive($array1, $array2, &$mismatches) {
foreach ($array1 as $key => $value) {
if (!isset($array2[$key])) {
$mismatches[$key] = [ $value ];
continue;
}
$value2 = $array2[$key];
if (!is_array($value) || !is_array($value2)) {
if ($value != $value2) {
$mismatches[$key] = [
$value, $value2
];
}
} else {
$mismatches_internal = [];
CompareRecursive($value, $value2, $mismatches_internal);
if (!empty($mismatches_internal)) {
$mismatches[$key] = $mismatches_internal;
}
}
}
return empty($mismatches);
}
As an added bonus this keeps track of mismatched entries too, there's a drawback when using this method that it won't work if $array2 has extra elements that $array1 doesn't but you can resolve this by doing:
$isEqual = CompareRecursive($array1,$array2) && CompareRecursive($array2,$array1);
Simple code is:
$arr2;
$arr1;
$eq = true;
if (count($arr1) == count($arr2)) {
foreach ($arr1 as $k => $v) {
if (empty($arr2[$k]) || $arr2[$k]['Gym'] != $v['Gym'] || $arr2[$k]['Library'] != $v['Library']) {
$eq = false;
break;
}
}
} else {
$eq = false;
}
var_dump($eq);
Update:
Without fixed keys inner foreach becomes:
foreach ($arr1 as $k => $v) {
if (empty($arr2[$k]) || array_diff_assoc($arr2[$k], $v)) {
$eq = false;
break;
}
}
function arrayTwoLevelEquivalence(array $a, array $b) {
if (count($a) !== count($b)) {
return false;
}
foreach ($a as $k => $a2) {
if (!isset($b[$k])) {
return false;
}
$b2 = $b[$k];
if (count($a2) !== count($b2)) {
return false;
}
foreach ($a2 as $k2 => $v) {
if (!array_key_exists($k2, $b2) || $b2[$k2] !== $v) {
return false;
}
}
}
return true;
}
I decline to use array_diff_assoc() because I do not support unnecessary transient allocation of heap memory for the sake of convenience.
$array1 = array("a" => "green", 'b'=>"red", 'c'=>"blue");
$array2 = array('b'=>"red", 'c'=>"blue", "a" => "green");
echo empty(array_diff_assoc($array1, $array2));
check it, hope it will fulfill your requirements. It will check if both associative array are same, whether it has same order or not.
Check it for your multidimensional array -
function array_diff_assoc_recursive($array1, $array2)
{
foreach($array1 as $key => $value)
{
if(is_array($value))
{
if(!isset($array2[$key]))
{
$difference[$key] = $value;
}
elseif(!is_array($array2[$key]))
{
$difference[$key] = $value;
}
else
{
$new_diff = array_diff_assoc_recursive($value, $array2[$key]);
if($new_diff != FALSE)
{
$difference[$key] = $new_diff;
}
}
}
elseif(!isset($array2[$key]) || $array2[$key] != $value)
{
$difference[$key] = $value;
}
}
return !isset($difference) ? 0 : $difference;
}
I have found it from here
If all you need to know is they match or not - without any further details:
function ksortRecursive(&$array)
{
if (is_array($array)) {
ksort($array);
foreach ($array as &$arr) {
ksortRecursive($arr);
}
}
}
ksortRecursive($arr1);
ksortRecursive($arr2);
if (serialize($arr1) == serialize($arr2)) {
echo "match!";
}
I have a multidimensional array like this:
$a['bla1']['blub1']="test123";
$a['bla1']['blub2']="test1234";
$a['bla1']['blub3']="test12345";
$a['bla2']['blub1']="test123456";
$a['bla2']['blub2']="test12344e45";
$a['bla2']['blub3']="test12345335";
How to search by value and get back bla1 or bla2? I don't need the subkey, only the key.
try this:
function searcharray($a, $value)
{
foreach($a as $key1 => $keyid)
{
foreach($keyid as $key => $keyid2)
{
if ( $keyid2 === $value )
return $key.','.$key1;
}
}
return false;
}
This function recursively searches an array to any depth and returns the main key under which $needle is found:
function get_main_key($arr, $needle) {
$out = FALSE;
foreach ($arr as $key => $value) {
if ($value == $needle) {
$out = $key;
} elseif (is_array($value)) {
$ret = get_main_key($value, $needle);
$out = ( ! empty($ret)) ? $key : $out;
}
}
return $out;
}
If I have an array:
Array
(
[0] =>
[1] => a
[2] => b
[3] => c
)
And I want to get the first non-null value from the array, in this case "a". How could I go about doing that nice and easily?
Not sure about nice and easy. But a short approach might be:
$first = current(array_filter($sparse_array));
Where array_filter will extract you the "truthy" values, thus skipping empty and false entries. While current simply gives you the first of those remaining entries.
function get_first_not_null($array){
foreach($array as $v){
if($v !== null){
return $v;
}
}
return null;
}
function getFirstNotNull($array) {
foreach($array as $val) {
if(!is_null($val) || !$val) return $val;
}
}
$res = null;
foreach ($arr as $v) {
if ($v !== null) {
$res = $v;
break;
}
}
Well, you could try this:
foreach($array as $x) {
if( $x) break;
}
if( $x) {
// $x is the first non-null value
}
else {
// There were no non-null values
}
I would use array_reduce
$firstNonNull = array_reduce($array, function($v, $w) {
return $v ? $v : (isset($w) ? $w : FALSE);
});
i would like to ask for your help since I'm having difficulty resolving this matter. I had created a function to facilitate on array diff but it does not suffice to my needs. Thanks and more power!
<?php
$arraySession = array(
'sampleA' => array('1', '2', '3'),
'sampleB' => array('1', '2', '3'),
);
$arrayPost = array(
'sampleA' => array('1'),
'sampleB' => array('1','2'),
);
result should be:
array(
'sampleA' => array('2', '3')
'sampleB' => array('3'),
)
my existing function:
public function array_diff_multidimensional($session, $post) {
$result = array();
foreach($session as $sKey => $sValue){
foreach($post as $pKey => $pValue) {
if((string) $sKey == (string) $pKey) {
$result[$sKey] = array_diff($sValue, $pValue);
} else {
$result[$sKey] = $sValue;
}
}
}
return $result;
}
Any help would be much appreciated! Happy coding!
Not my function and not tested by me, but this was one of the first comments at php.net/array_diff (credit goes to thefrox at gmail dot com)
<?php
function multidimensional_array_diff($a1, $a2) {
$r = array();
foreach ($a2 as $key => $second) {
foreach ($a1 as $key => $first) {
if (isset($a2[$key])) {
foreach ($first as $first_value) {
foreach ($second as $second_value) {
if ($first_value == $second_value) {
$true = true;
break;
}
}
if (!isset($true)) {
$r[$key][] = $first_value;
}
unset($true);
}
} else {
$r[$key] = $first;
}
}
}
return $r;
}
?>
This should do it, assuming all keys occur in both arrays:
$diff = array();
foreach ($session as $key => $values) {
$diff[$key] = array_diff($values, $post[$key]);
}
Or, because I'm bored and array_map is underused:
$diff = array_combine(
array_keys($session),
array_map(function ($a, $b) { return array_diff($a, $b); }, $session, $post)
);
(Assumed well ordered arrays though.)
You want something more or less like this:
public function array_diff_multidimensional($arr1, $arr2) {
$answer = array();
foreach($arr1 as $k1 => $v1) {
// is the key present in the second array?
if (!array_key_exists($k1, $arr2)) {
$answer[$k1] = $v1;
continue;
}
// PHP makes all arrays into string "Array", so if both items
// are arrays, recursively test them before the string check
if (is_array($v1) && is_array($arr2[$k1])) {
$answer[$k1] = array_diff_multidimensional($v1, $arr2[$k1]);
continue;
}
// do the array_diff string check
if ((string)$arr1[$k1] === (string)$arr2[$k1]) {
continue;
}
// since both values are not arrays, and they don't match,
// simply add the $arr1 value to match the behavior of array_diff
// in the PHP core
$answer[$k1] = $v1;
}
// done!
return $answer;
}
Hi i have a multidimensional associative array:
$array= array(
'Book1' => array('http://www.google.com', '45' ),
'Book2' => array('http://www.yahoo.com', '46', )
)
I need to be able to search $array on 'BookX' and then return the contents of 'BookX'.
Ive tried:
function array_searcher($needles, $array)
{
foreach ($needles as $needle) {
foreach ($array as $key )
{
if ($key == $needle)
{
echo $key;
}
}
}
}
with the search
$needles = array('Book1' , 'Book2' );
But this doesnt return anything
I might be misunderstanding, but this just sounds like the accessor. If not, could you clarify?
$array= array(
'Book1' => array('http://www.google.com', '45' ),
'Book2' => array('http://www.yahoo.com', '46', )
);
echo $array['Book1'];
EDIT: I did misunderstand your goal. I do have a comment on doing the two foreach loops. While this does work, when you have a very large haystack array, performance suffers. I would recommend using isset() for testing if a needle exists in the haystack array.
I modified the function to return an array of the found results to remove any performance hits from outputing to stdout. I ran the following performance test and while it might not do the same search over and over, it points out the inefficiency of doing two foreach loops when your array(s) are large:
function array_searcher($needles, $array) {
$result = array();
foreach ($needles as $needle) {
foreach ($array as $key => $value) {
if ($key == $needle) {
$result[$key] = $value;
}
}
}
return $result;
}
function array_searcher2($needles, $array) {
$result = array();
foreach ($needles as $needle) {
if (isset($array[$needle])) {
$result[$needle] = $array[$needle];
}
}
return $result;
}
// generate large haystack array
$array = array();
for($i = 1; $i < 10000; $i++){
$array['Book'.$i] = array('http://www.google.com', $i+20);
}
$needles = array('Book1', 'Book2');
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
array_searcher($needles, $array);
}
echo (microtime(true) - $start)."\n";
// 14.2093660831
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
array_searcher2($needles, $array);
}
echo (microtime(true) - $start)."\n";
// 0.00858187675476
If you want to search using the keys, you should access it as a key => value pair.
If you don't it only retrieves the value.
function array_searcher($needles, $array)
{
foreach ($needles as $needle)
{
foreach ($array as $key => $value)
{
if ($key == $needle)
{
echo $key;
}
}
}
}