PHP - Mutidimensional array diff - php

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

Related

Check if associative multi-dimensional arrays are equal regardless of order of keys in either level [duplicate]

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

Split an array by key

I have an array with the following keys:
Array
{
[vegetable_image] =>
[vegetable_name] =>
[vegetable_description] =>
[fruit_image] =>
[fruit_name] =>
[fruit_description] =>
}
and I would like to split them based on the prefix (vegetable_ and fruit_), is this possible?
Currently, I'm trying out array_chunk() but how do you store them into 2 separate arrays?
[vegetables] => Array { [vegetable_image] ... }
[fruits] => Array { [fruit_image] ... }
This should work for you:
$fruits = array();
$vegetables = array();
foreach($array as $k => $v) {
if(strpos($k,'fruit_') !== false)
$fruits[$k] = $v;
elseif(strpos($k,'vegetable_') !== false)
$vegetables[$k] = $v;
}
As an example see: http://ideone.com/uNi54B
Out of the Box
function splittArray($base_array, $to_split, $delimiter='_') {
$out = array();
foreach($to_split as $key) {
$search = $key.delimiter;
foreach($base_array as $ok=>$val) {
if(strpos($ok,$search)!==false) {
$out[$key][$ok] = $val;
}
}
return $out;
}
$new_array = splittArray($array,array('fruit','vegetable'));
It is possible with array_reduce()
$array = ['foo_bar' => 1, 'foo_baz' => 2, 'bar_fee' => 6, 'bar_feo' => 9, 'baz_bee' => 7];
$delimiter = '_';
$result = array_reduce(array_keys($array), function ($current, $key) use ($delimiter) {
$splitKey = explode($delimiter, $key);
$current[$splitKey[0]][] = $key;
return $current;
}, []);
Check the fiddle
Only one thins remains: you are using different forms (like "vegetable_*" -> "vegetables"). PHP is not smart enough to substitute language (that would be English language in this case) transformations like that. But if you like, you may create array of valid forms for that.
Use explode()
$arrVeg = array();
$arrFruit = array();
$finalArr = array();
foreach($array as $k => $v){
$explK = explode('_',$k);
if($explK[0] == 'vegetable'){
$arrVeg[$k] = $v;
} elseif($explK[0] == 'fruit') {
$arrFruit[$k] = $v;
}
}
$finalArr['vegetables'] = $arrVeg;
$finalArr['fruits'] = $arrFruit;
Use simple PHP array traversing and substr() function.
<?php
$arr = array();
$arr['vegetable_image'] = 'vegetable_image';
$arr['vegetable_name'] = 'vegetable_name';
$arr['vegetable_description'] = 'vegetable_description';
$arr['fruit_image'] = 'fruit_image';
$arr['fruit_name'] = 'fruit_name';
$arr['fruit_description'] = 'fruit_description';
$fruits = array();
$vegetables = array();
foreach ($arr as $k => $v) {
if (substr($k, 0, 10) == 'vegetable_') {
$vagetables[$k] = $v;
}
else if (substr($k, 0, 6) == 'fruit_') {
$fruits[$k] = $v;
}
}
print_r($fruits);
print_r($vagetables);
Working Example

Accessing the nth element in multidimensional array

is there a simple way to access the nth element in a multidimensional array in php?
so for example
$arr = array(
[0] => array(1,4,7,3,53),
[6] => array(6,3,9,12,51,7),
[2] => array(9,94,54,3,87));
the 12th element would be 9.
array keys are not necessarily in order, nor each array row is of the same length.
Try this :
<?php
$arr = array(
'0'=> array(1,4,7,3,53),
'6'=>array(6,3,9,12,51,7),
'2'=>array(9,94,54,3,87)
);
$newArray=array();
foreach($arr as $array){
$newArray=array_merge($newArray, $array);
}
echo $newArray[11];
?>
untested, should work...
$arr = array(
0 => array(1,4,7,3,53), // your code was wrong here
6 => array(6,3,9,12,51,7),
2 => array(9,94,54,3,87));
function getnth ($array, $offset) {
$tmp_arr = array();
foreach ($array as $key => $value) {
foreach ($value as $val) {
$tmp_arr[] = $val;
}
}
return (isset($tmp_arr[$offset -1]) ? $tmp_arr[$offset -1] : FALSE);
}
getnth($arr, 12);
Edit: got to admit, the array_merge version is better....
Edit2: this is probably faster, if performance is an issue....
function getnth($array, $offset) {
$i = 0;
foreach ($array as $key => $value){
$size = count($value);
$i += $size;
if($offset <= $i) {
$new_off = $size - ($i - $offset) -1 ;
return $value[$new_off];
}
}
return FALSE;
}
function get_item($arr, $path, $delim = '.') {
$path = explode($delim, $path);
$result = $arr;
foreach ($path as $item) {
if (isset($result[$item])) {
$result = $result[$item];
} else {
return null;
}
}
return $result;
}
using:
echo get_item($arr, 'item.value.3.4.2.etc');

PHP Search multidimensional associative array by key and return key => value

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

Remove Parent in PHP Multidimensional Array

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.

Categories