Compare Dynamic Multidimensional Arrays - php

I have two multidimensional dynamic arrays like so in PHP:
$old = array(
"meta_data" => array(
"page_title" => "Test1",
"page_description" => "Test2",
"page_keywords" => "Test3"
),
"content" => array(
"page_header_one" => "1",
"page_content_one" => "2",
"page_header_two" => "3",
"page_content_two" => "4",
"page_header_three" => "5"
),
);
$new = array(
"meta_data" => array(
"page_title" => "Test1",
"page_description" => "Test2",
"page_keywords" => "Test3324"
),
"content" => array(
"page_header_one" => "124",
"page_content_one" => "243",
"page_header_two" => "343"
),
);
I'm struggling to compare these as they're dynamic, e.g. the keys change. What I'm aiming to do is compare the arrays, find out what's changed, leave out keys that don't match, and only add the changes to the new array.
The only things that will be constant are "meta_data" and "content"
So for example in $old we have 5 items in the content array, but in the $new array we only have 3 items (3 changed items), so the new array would have 3 content items.
Is there a way to do this I can't for the life in me figure out how?
Final array should look like so:
$final = array(
"meta_data" => array(
"page_keywords" => "Test3324"
),
"content" => array(
"page_header_one" => "124",
"page_content_one" => "243",
"page_header_two" => "343"
),
);

Maybe it can be done easier, but I think this will do the job:
<?php
$newArray = [];
foreach($old['meta_data'] as $key => $value) {
if(array_key_exists($key, $new['meta_data'])) {
if($new['meta_data'][$key] == $old['meta_data'][$key]) {
$newArray['meta_data'][$key] = $value;
}
}
}
foreach($old['content'] as $key => $value) {
if(array_key_exists($key, $new['content'])) {
if($new['content'][$key] == $old['content'][$key]) {
$newArray['content'][$key] = $value;
}
}
}
You can also make the top key dynamic, so content and meta_data are dynamic as well, like this:
foreach($old as $topKey => $subArray) {
if(array_key_exists($topKey, $new)) {
foreach($subArray as $key => $value) {
if(array_key_exists($key, $new[$topKey])) {
if($new[$topKey][$key] == $old[$topKey][$key]) {
$newArray[$topKey][$key] = $value;
}
}
}
}
}
I haven't tested it. But I think you'll get the gist.

The only things that will be constant are "meta_data" and "content"
Given this thing in mind, the solution to your problem would be to use array_diff() function like this:
$final = array();
$final['meta_data'] = array_diff($new['meta_data'], $old['meta_data']);
$final['content'] = array_diff($new['content'], $old['content']);
// display $final array
var_dump($final);
Here's a live demo

You can simply use the PHP array_diff() function.
$final = array_diff($new, $old);

Related

Assign values in array based on array keys

How to modify an array based on the value as key?
array(
array(
"name" => "BIBAR",
"cutoff" => 20220725,
"totals" => 5614
),
array(
"name" => "BIBAR",
"cutoff" => 20220810,
"totals" => 5614
),
array(
"name" => "BIBAR",
"cutoff" => 20220825,
"totals" => 5614
)
);
I tried the following but it's not working:
foreach($cutoffs as $catoff) {
$ii = 0;
$sums[$ii][$catoff] = array_filter($array, function($val){
return $val['cutoff'] === $catoff ? $val['totals'] : $val;
});
$ii++;
}
My desired array:
array(
'20221025' => array(
12345,
12343,
24442
),
'20221110' => array(
3443,
744334
)
)
I'm stuck here for hours ... Please help
IF the "name" is irrelevant, I think also the previous answer should be fine.
If this code does "not work", then your explanation might be wrong, so you need to either explain better, or give us more examples - please mind that in your example the input and output are very different - the input you gave does not match your ouput.
My code is:
$a = array(
array(
"name" => "BIBAR",
"cutoff" => 20220725,
"totals" => 5614
),
array(
"name" => "BIBAR",
"cutoff" => 20220810,
"totals" => 5614
),
array(
"name" => "BIBAR",
"cutoff" => 20220725,
"totals" => 1234
)
);
print_r($a);
echo "\n================================\n\n";
$newArr = [];
foreach ($a as $k => $vArr) {
// maybe some validation would be useful here, check if they keys exist
$newArr[$vArr['cutoff']][] = $vArr['totals'];
}
print_r($newArr);
function changeArr($data){
$new = [];
foreach ($data as $v){
$new[$v['cutoff']][] = $v['totals'];
}
return $new;
}

PHP create JSON with foreach

I have following PHP code, to create JSON with foreach out of an array:
$array = array('one', 'two', 'three', 'four');
foreach ($array as $key => $value) {
$temp = array(
'text' => 'Hello',
'text1' => 5,
'collect' => array(
$value => array(
'xx' => 'yy',
'key' => $key
)
)
);
echo json_encode($temp);
}
The Output is this:
{
"text":"Hello",
"text1":5,
"collect":{"one":{"xx":"yy","key":0}}
}
{
"text":"Hello",
"text1":5,
"collect":{"two":{"xx":"yy","key":1}}
}
{
"text":"Hello",
"text1":5,
"collect":{"three":{"xx":"yy","key":2}}
}
{
"text":"Hello",
"text1":5,
"collect":{"four":{"xx":"yy","key":3}}
}
But i want this:
{
"text":"Hello",
"text1":5,
"collect": {
"one":{"xx":"yy","key":0},
"two":{"xx":"yy","key":1},
"three":{"xx":"yy","key":2},
"four":{"xx":"yy","key":3}
}
}
I get single 4 single JSON Objects, but i need only one with an collect object.
I don't get it...
I'd like to educate readers on a couple alternative methods as well as highlight that the other two answers needlessly instantiate the collect subarray prior to the loop (Sahil's answer does this twice for some reason).
The initial input array and the static elements of the result array should be placed at the start as the other answers do. Purely due to personal preference, I'll be using short array syntax.
Inputs:
$array=['one','two','three','four'];
$result=['text'=>'Hello','text1'=>5]; // <-- no 'comment' element declared
Now for the different methods that traverse $array and build the dynamic elements of the result.
Method #1: array_walk()
array_walk($array,function($v,$k)use(&$result){
$result['collect'][$v]=['xx'=>'yy','key'=>$k];
});
Method #2: array_map()
array_map(function($k,$v)use(&$result){
$result['collect'][$v]=['xx'=>'yy','key'=>$k];
},array_keys($array),$array);
Array map is less efficient because it requires an additional array to be passed to the function.
Method #3: foreach()
foreach($array as $k=>$v){
$result['collect'][$v]=['xx'=>'yy','key'=>$k];
}
$result at this point looks like this:
array (
'text' => 'Hello',
'text1' => 5,
'collect' => array (
'one' => array ( 'xx' => 'yy', 'key' => 0 ),
'two' => array ( 'xx' => 'yy', 'key' => 1 ),
'three' => array ( 'xx' => 'yy', 'key' => 2 ),
'four' => array ( 'xx' => 'yy', 'key' => 3 )
)
)
foreach() is the simplest and easiest to read for this case, but it important to understand and compare versus php's array functions to ensure you are using the best method for any given project.
For anyone wondering what the & is doing in use(&$result), that is a reference which is used in the anonymous function (aka closure) to make the $result variable "modifiable" within the function.
Finally convert to json using json_encode() and display with echo:
echo json_encode($result);
All of the above methods product the same desired output:
{"text":"Hello","text1":5,"collect":{"one":{"xx":"yy","key":0},"two":{"xx":"yy","key":1},"three":{"xx":"yy","key":2},"four":{"xx":"yy","key":3}}}
Here is the Demo of all three methods
Try this simple code ,in which we have a declaration before foreach.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$array = array('one', 'two', 'three', 'four');
$temp = array(
'text' => 'Hello',
'text1' => 5,
'collect' => array()
);
$collect = array();
foreach ($array as $key => $value)
{
$collect[$value] = array(
'xx' => 'yy',
'key' => $key
);
}
$temp["collect"]=$collect;
echo json_encode($temp);
Output:
{
"text": "Hello",
"text1": 5,
"collect": {
"one": {
"xx": "yy",
"key": 0
},
"two": {
"xx": "yy",
"key": 1
},
"three": {
"xx": "yy",
"key": 2
},
"four": {
"xx": "yy",
"key": 3
}
}
}
You need to loop through and append these value arrays to the 'collect' key of your temp array.
$array = array('one', 'two', 'three', 'four');
$temp = array(
'text' => 'Hello',
'text1' => 5,
'collect' => array()
);
foreach ($array as $key => $value) {
$temp['collect'][$value] = array(
'xx' => 'yy',
'key' => $key
);
}
echo json_encode($temp);
Here is the demo: https://eval.in/788929

Remove duplicates from a multidimensional array based on multiple keys

Sorry if this was asked before, but I searched a lot and couldn't find a solution.
I've been trying to solve this problem for a while now, and couldn't write the function for it.
I have an array like that:
$numbers = array(
array("tag" => "developer", "group" => "grp_1", "num" => "123123"),
array("tag" => "developer", "group" => "grp_2", "num" => "111111"),
array("tag" => "student", "group" => "grp_1", "num" => "123123"),
array("tag" => "student", "group" => "grp_2", "num" => "123123"),
array("tag" => "developer", "group" => "grp_3", "num" => "111111"),
);
I need to write a function, that removes the duplicates off this array, based on multiple keys, so my function call should look something like that:
unique_by_keys($numbers, array("num","group"));
In other terms, one number can't be in the same group more than once.
After calling unique_by_keys() by array should be like that:
$numbers = array(
array("tag" => "developer", "group" => "grp_1", "num" => "123123"),
array("tag" => "developer", "group" => "grp_2", "num" => "111111"),
array("tag" => "student", "group" => "grp_2", "num" => "123123"),
array("tag" => "developer", "group" => "grp_3", "num" => "111111"),
);
I'd appreciate if you could help me find a solution, or lead me to the correct way of thinking.
Thanks!
SOLUTION:
I was able to find a solution, by writing the following function:
( I wrote it in a way that accepts many forms of $haystack arrays )
function unique_by_keys($haystack = array(), $needles = array()) {
if (!empty($haystack) && !empty($needles)) {
$_result = array();
$result = array();
$i = 0;
foreach ($haystack as $arrayObj) {
if (is_array($arrayObj)) {
$searchArray = array();
foreach ($needles as $needle) {
if (isset($arrayObj[$needle])) {
$searchArray[$needle] = $arrayObj[$needle];
}
}
if (!in_array($searchArray, $_result)) {
foreach ($arrayObj as $key => $value) {
if (in_array($key, $needles)) {
$_result[$i][$key] = $value;
}
}
$result[] = array_merge($_result[$i], $arrayObj);
}
} else {
$result[] = $arrayObj;
}
$i++;
}
return $result;
}
}
Thanks for everyone that replied!
Bhaskar's approach which assigns unique keys in the loop to remove duplicates affords a very small function for this case.
Here is a previous and unnecessarily complicated version:
function unique_by_keys($haystack=array(),$needles=array()){
// reverse order of sub-arrays to preserve lower-indexed values
foreach(array_reverse($haystack) as $row){
$result[implode('',array_intersect_key($row,array_flip($needles)))]=$row; // assign unique keys
}
ksort($result); // sort the sub-arrays by their assoc. keys
return array_values($result); // replace assoc keys with indexed keys
}
This is the best/leanest solution I can come up with:
$numbers = array(
array("tag" => "developer", "group" => "grp_1", "num" => "123123"),
array("tag" => "developer", "group" => "grp_2", "num" => "111111"),
array("tag" => "student", "group" => "grp_1", "num" => "123123"),
array("tag" => "student", "group" => "grp_2", "num" => "123123"),
array("tag" => "developer", "group" => "grp_3", "num" => "111111")
);
function unique_by_keys($haystack=array(),$needles=array()){
foreach($haystack as $row){
$key=implode('',array_intersect_key($row,array_flip($needles))); // declare unique key
if(!isset($result[$key])){$result[$key]=$row;} // save row if non-duplicate
}
return array_values($result);
}
echo "<pre>";
var_export(unique_by_keys($numbers,array("group","num")));
echo "</pre>";
Output:
array (
0 =>
array (
'tag' => 'developer',
'group' => 'grp_1',
'num' => '123123',
),
1 =>
array (
'tag' => 'developer',
'group' => 'grp_2',
'num' => '111111',
),
2 =>
array (
'tag' => 'student',
'group' => 'grp_2',
'num' => '123123',
),
3 =>
array (
'tag' => 'developer',
'group' => 'grp_3',
'num' => '111111',
),
)
$newNumbers = array();
foreach($numbers as $key=>$values){
$newkey = $values['group'].'__'.$values['num'];
$newNumbers[$newkey] = $values;
}
var_dump($newNumbers)
Code might not be efficient, but i will work for you :)
$result = unique_by_keys($numbers, array("num","group"));
echo "<pre>";
print_R($result);
function unique_by_keys($numbers, $arr){
$new_array = array();
$output = array();
foreach ($numbers as $n){
if(isset($new_array[$n[$arr[1]]]) && $new_array[$n[$arr[1]]] == $n[$arr[0]]){
continue;
}else{
$new_array[$n[$arr[1]]] = $n[$arr[0]];
$output[] = $n;
}
}
return $output;
}

Not getting array all values using php

I have this following array
$question = array(
"ques_15" => array(
"name" => array(
"0" => "aaa"
)
),
"ques_16" => array(
"name" => array(
"0" => "bbb",
"1" => "ccc"
)
)
);
$i=0;
foreach($question as $k=>$v)
{
echo $question[$k]['name'][$i];
$i++;
}
But my output is only
aaaccc
I am missing the value bbb
You need to iterate the inner 'name' arrays - you could use a nested foreach loop:
$question = array(
"ques_15" => array(
"name" => array(
"0" => "aaa"
)
),
"ques_16" => array(
"name" => array(
"0" => "bbb",
"1" => "ccc"
)
)
);
foreach($question as $quest)
{
foreach($quest['name'] as $val)
{
echo $val;
}
}
you should loop though like so
foreach($question as $q)
{
foreach($q['name'] as $v)
{
echo $v;
}
}
in foreach you don't need a counter $i, it's for while() or for()
you array is two dimensional so you need 2 foreach
Check it out in a functional way.
The shorthand array declaration works only on PHP 5.4+ though, but it still works with your longhand array declaration.
$questions = [
'ques_15' => ['name' => ['aaa']],
'ques_16' => ['name' => ['bbb', 'ccc']]
];
array_map(function($a){
foreach ($a['name'] as $v) echo $v;
}, $questions);

Find index in Multidimensional Array

Basically I have this array:
array(
[0] => array("id" => "0", "header" => "img1"),
[1] => array("id" => "4", "header" => "img4")
[2] => array("id" => "6", "header" => "img6")
)
If I have $id = "4", how can I extract the index [1] to obtain "header" value?
You will want to do a foreach loop for this. But honestly if you structured your array indexes better than you could just to a simple isset test and then grab the value once you verify it is there.
The right way:
$headers = array(0 => 'img1', 4 => 'img4', 6 => 'img6');
if (isset($headers[$index])) {
return $headers[$index];
}
Here is how to deal with it with your array (much more costly from a processing standpoint):
$headers = array(
0 => array("id" => "0", "header" => "img1"),
1 => array("id" => "4", "header" => "img4"),
2 => array("id" => "6", "header" => "img6")
);
foreach ($headers AS $value) {
if ($value['id'] == $index) {
return $value['header'];
}
}
foreach ($array as $key => $value) {
if ($value['id'] == '4') {
echo $value['header'];
break;
}
}
It will be better to store id and header like this for example:
array(
"0" => "img1",
"4" => "img4",
"6" => "img6",
);
Arrays in PHP are actually hash tables behind the scenes, so accessing elements by key is extremely fast. If you can, change the way your array is created at the source to use the id (which I assume is unique) as the key, as already mentioned in other answers.
To transform your current array to be indexed by id, you could use this code:
$indexed = array();
foreach($array as $element) {
$indexed[$element['id']] = $element['header'];
}
// $indexed now resembles id => header
You can then access header values in constant time using $indexed[$id].

Categories