How to compare two associative arrays by key - php

I am trying to compare two associative arrays and get the difference based upon the value and also based upon the key. I have tried using an array_filter with a closure
The two arrays are like so:
Array 1
$newArr = [
0 => [
'id' => 'UT5',
'qty' => '4'
],
1 => [
'id' => 'WRO',
'qty' => '3'
],
2 => [
'id' => 'SHO',
'qty' => '3'
]
];
Array 2
$oldArr = [
0 => [
'id' => 'SHO',
'qty' => '1'
],
1 => [
'id' => 'UT5',
'qty' => '2'
],
];
My desired output is as follows:
array(3)
{
["UT5"]=> int(2)
["SHO"]=> int(2)
["WRO"]=> int(3)
}
I have gotten this far:
<?php
$newArr = [
0 => [
'id' => 'UT5',
'qty' => '4'
],
1 => [
'id' => 'WRO',
'qty' => '3'
],
2 => [
'id' => 'SHO',
'qty' => '3'
]
];
$oldArr = [
0 => [
'id' => 'SHO',
'qty' => '1'
],
1 => [
'id' => 'UT5',
'qty' => '2'
],
];
$toAdd = [];
foreach ($newArr as $item) {
$itemsToAdd = array_walk($oldArr, function ($k) use ($item, &$toAdd) {
if ($k['id'] == $item['id']) {
$toAdd[$k['id']] = max($k['qty'], $item['qty']) - min($k['qty'], $item['qty']);
}
});
}
var_dump($toAdd); die();
However with this function, my current output is:
array(2) {
["UT5"]=> int(2)
["SHO"]=> int(2)
}
Note that WRO is missing. Is there a way that I can add a conditional to accurately check for this? I have tried a few solution such as !in_array and else but neither are giving me the desired output.
Any help is appreciated! Thanks!

That's an easy one, your code saves a value ONLY if the key is present in both arrays. Just add a clause to check if the key DOESN'T exist in the old array. (also do the opposite in case the old array has a key the new one doesn't have)
if (!isset(old array [ new array key ]){
$newArray[new array key] = new array key and values;
Your program structure is optimized for the computer and is too complex to follow as a human, I rewrote it entirely.
<?php
$newArr = [0 => ['id' => 'UT5', 'qty' => '4'], 1 => ['id' => 'WRO', 'qty' => '3'], 2 => ['id' => 'SHO', 'qty' => '3']];
$oldArr = [0 => ['id' => 'SHO', 'qty' => '1'], 1 => ['id' => 'UT5', 'qty' => '2'], ];
$newReset = [];
foreach( $newArr as $item ) {
$newReset[$item['id']] = $item['qty'];
}
$oldReset = [];
foreach( $oldArr as $item ) {
$oldReset[$item['id']] = $item['qty'];
}
foreach( $newReset as $key => $val ) {
if( isset( $oldReset[$key] ) ) {
$toAdd[$key] = max( $oldReset[$key], $val ) - min( $oldReset[$key], $val );
}
else $toAdd[$key] = intval($val);
}
var_dump( $toAdd );
And here's the result.
array(3) {
["UT5"]=>
int(2)
["WRO"]=>
int(3)
["SHO"]=>
int(2)
}

Make it in one pass
$toAdd = [];
foreach ($newArr as $item)
$toAdd[$item['id']] = $item['qty'];
foreach ($oldArr as $item)
if (isset($toAdd[$item['id']]))
$toAdd[$item['id']] = abs($toAdd[$item['id']] - $item['qty']);
else
$toAdd[$item['id']] = abs($item['qty']);
print_r($toAdd);

Related

Where two id matching, erase the value in two arrays

I have two arrays like this :
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
I would like to put the value in $data in the value of $data2 instead of "null" values where the ID are matching.
How can I do this ?
I try to do this but does not work :
foreach ($data2['custom'] as $d) {
foreach ($data as $cf) {
if ($cf['id'] == $d['id']):
$cf['value'] = $d['value'];
endif;
}
}
Thanks
Here is a suggestion, first transform the $data array into an array with the id as a key to make the following process simple.
Then process over the $data2 array and in the foreach us the & reference indicator, so that amendments inside the foreach loop are applied to the original $data2 array and not the copy of the $data2 array that would normally be created as part of a foreach loop
$data = [ ['id' => 123, 'value' => 'Text'],['id' => 124, 'value' => 12] ];
$data2 = [ "custom" => [
['id' => 123, 'name' => 'Custom1', 'value' => null],
['id' => 124, 'name' => 'Custom2', 'value' => null]]
];
// transform $data into an array with a useful key
foreach( $data as $d){
$useful[$d['id']] = $d['value'];
}
foreach ( $data2['custom'] as &$data ) {
// first check that the id exists in the new useful array
if ( isset($useful[$data['id']]) ) {
// if it does apply the value to the data2 array
$data['value'] = $useful[$data['id']];
}
}
print_r($data2);
RESULT
Array
(
[custom] => Array
(
[0] => Array
(
[id] => 123
[name] => Custom1
[value] => Text
)
[1] => Array
(
[id] => 124
[name] => Custom2
[value] => 12
)
)
)
In reply to your comment about doing it without using the reference in the loop, yes like this
foreach ( $data2['custom'] as $idx => $data ) {
if ( isset($useful[$data['id']]) ) {
$data2['custom'][$idx]['value'] = $useful[$data['id']];
}
}
Check out this one:
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
foreach ($data2['custom'] as $d) {
foreach ($data as $key => $cf) {
if ($cf['id'] == $d['id']):
$data2['custom'][$key]['value'] = $cf['value'];
endif;
}
}
print_r($data2);
You could try to iterate the first array and put the values of it inside the second. If they're always the same size.
Using a foreach go trough the elements on the first array and get the values:
$data = [
0 => ['id' => 123, 'value' => 'Text'],
1 => ['id' => 124, 'value' => 12
]
];
$data2 = [
"custom" => [
0 => ['id' => 123, 'name' => 'Custom1', 'value' => null],
1 => ['id' => 124, 'name' => 'Custom2', 'value' => null]
]
];
foreach ($data as $key=>$singleData){
$data2['custom'][$key]['value'] = $singleData['value'];
}
var_dump($data2);
The ouptup from var_dump() will be:
array(1) {
["custom"]=>
array(2) {
[0]=>
array(3) {
["id"]=>
int(123)
["name"]=>
string(7) "Custom1"
["value"]=>
string(4) "Text"
}
[1]=>
array(3) {
["id"]=>
int(124)
["name"]=>
string(7) "Custom2"
["value"]=>
int(12)
}
}
}

Counting occurrences in an array that has more than 1 key

I'm trying to get the occurrences of an array taking in count 1 key value, for example:
$newarray[0] = [
'id' => '2',
'date' => '2016-04-22'
];
$newarray[1] = [
'id' => '2',
'date' => '2016-04-13'
];
$newarray[2] = [
'id' => '2',
'date' => '2016-04-12'
];
$newarray[3] = [
'id' => '1',
'date' => '2016-03-11'
];
$newarray[4] = [
'id' => '2',
'date' => '2016-03-05'
];
$newarray[5] = [
'id' => '1',
'date' => '2016-03-01'
];
I want to transform this, to something like this:
Array ( [0] => Array ( [id] => 1 [date] => 2016-03-11 [occurences] => 2 ) [1] => Array ( [id] => 2 [date] => 2016-04-22 [occurences] => 4 ) )
I tried doing this:
$cleanarray;
$newarray2=$newarray;
$newarray;
$k=0;
$num=1;
for($i=0; $i<count($newarray); $i++){
for($j=1; $j<count($newarray2); $j++){
if($newarray2[$j]["id"]==$newarray[$i]["id"]){
$num++;
}
}
$cleanarray[$k] = [
'id' => $newarray[$i]["id"],
'date' => $newarray[$i]["date"],
'occurences' => $num
];
$k++;
$num=0;
}
But a lot of items repeat, with the same occurrences but several times, and in other cases the repeated items (with same id) would have different occurrences, so I don't know what can I do, I know that there is a function of:
$occurences = array_count_values($array);
But it doesn't work in this case, how can I approach to the solution?
I know what are you looking for, but I think this could solve your problems:
$newarray[0] = [
'id' => '2',
'date' => '2016-04-22'
];
$newarray[1] = [
'id' => '2',
'date' => '2016-04-12'
];
$newarray[2] = [
'id' => '2',
'date' => '2016-04-12'
];
$newarray[3] = [
'id' => '1',
'date' => '2016-03-11'
];
$newarray[4] = [
'id' => '2',
'date' => '2016-03-05'
];
$newarray[5] = [
'id' => '1',
'date' => '2016-03-01'
];
foreach($newarray as $key => $value){
if(isset($found[$value['id']][$value['date']])) {
$found[$value['id']][$value['date']]++;
} else {
$found[$value['id']][$value['date']] = 1;
}
}
print_r($found);
this will return something like:-
Array
(
[2] => Array
(
[2016-04-22] => 1
[2016-04-12] => 2
[2016-03-05] => 1
)
[1] => Array
(
[2016-03-11] => 1
[2016-03-01] => 1
)
)
Using temporary keys for this process will be the most performant way. Temporary keys simplify the output array task, requiring less and faster checking. If you wish to sort on id after the result array is generated, the temporary keys allow a simple ksort() call.
Code: (Demo)
$newarray=[
['id' => '2','date' => '2016-04-22'],
['id' => '2','date' => '2016-04-13'],
['id' => '2','date' => '2016-04-12'],
['id' => '1','date' => '2016-03-11'],
['id' => '2','date' => '2016-03-05'],
['id' => '1','date' => '2016-03-01']
];
foreach($newarray as $a){
if(!isset($result[$a['id']])){
$result[$a['id']]=array_merge($a,['occurrences'=>1]); // use id as temp key, preserve first found date
}else{
++$result[$a['id']]['occurrences']; // only update occurrences to preserve date
}
}
ksort($result); // optionally sort on id ASC
var_export(array_values($result)); // remove temporary keys from first level and print to screen
Output:
array (
0 =>
array (
'id' => '1',
'date' => '2016-03-11',
'occurrences' => 2,
),
1 =>
array (
'id' => '2',
'date' => '2016-04-22',
'occurrences' => 4,
),
)
You can do it like below:-
$final_array = array();
foreach($newarray as $arr){
if(!in_array($arr['id'],array_keys($final_array))){
$final_array[$arr['id']] = $arr;
$final_array[$arr['id']]['occurences'] = 1;
}else{
$final_array[$arr['id']]['occurences'] += 1;
}
}
$final_array= array_values($final_array);
print_r($final_array);
Output:- https://eval.in/847242
Note:- if you want final array to be ascending order of id then use usort() function like below:-
function cmpId($a, $b) {
return ($a['id'] - $b['id']);
}
usort($final_array, "cmpId");
print_r($final_array);
Output:- https://eval.in/847245

Need to push the key and value inside associative Array?

I need to push the more key and its value inside the array. If I use below code first key pair replaced by 2nd one.
For your Reference:
Code Used:
foreach ($projectData['projectsections'] as $key => $name) {
$projectData['projectsections'][$key] = ['name' => $name];
$projectData['projectsections'][$key]= ['id' => '1'];
}
Current result:
'projectsections' => [
(int) 0 => [
'id' => '1'
],
(int) 1 => [
'id' => '1'
]
],
Expected:
'projectsections' => [
(int) 0 => [
'name' => 'test1',
'id' => '1'
],
(int) 1 => [
'name' => 'test2',
'id' => '1'
]
],
How can I build this array in PHP?? Any one help??
You need to either add the entire array:
$projectData['projectsections'][$key] = ['name' => $name, 'id' => '1'];
Or add with the key name:
$projectData['projectsections'][$key]['name'] = $name;
$projectData['projectsections'][$key]['id'] = '1';
With
$projectData['projectsections'][$key] = ['name' => $name];
$projectData['projectsections'][$key]= ['id' => '1'];
you are setting a new Array for that $key. This is not what you want.
This should work:
$projectData['projectsections'][$key] = ['name' => $name, 'id' => '1'];
Change it to :
foreach ($projectData['projectsections'] as $key => $name) {
$projectData['projectsections'][$key]['name'] = $name;
$projectData['projectsections'][$key]['id'] = '1';
}

Sorting array in PHP based on another array indexes

I have two arrays
// array of objects
$records = array(
[0] => (object) [
'id' => 1, // (*)
....
],
[1] => (object) [
'id' => 2, // (*)
....
],
[2] => (object) [
'id' => 3, // (*)
....
],
);
// array 2
// the keys in this array refer to the object ids (*)
$sorted = array(
'2' => 7,
'3' => 4,
'1' => 2,
);
$new_records = array();
What I want to do is to sort the values of first array (i.e the objects) based on the order of the key index of the second array, so the end result in this case will become:
$new_records = array(
[0] => (object) [
'id' => 2,
....
],
[1] => (object) [
'id' => 3,
....
],
[2] => (object) [
'id' => 1,
....
],
);
$records = $new_records;
Try this
$new_records = array();
foreach( $sort as $id => $pos ) {
foreach( $records as $record ) {
if( $record[ 'id' ] == $id ) {
$new_records[] = $record;
break;
}
}
}
This make the job
$records = array(
0 => (object) [
'id' => 1, // (*)
],
1 => (object) [
'id' => 2, // (*)
],
2 => (object) [
'id' => 3, // (*)
],
);
// array 2
// the keys in this array refer to the object ids (*)
$sorted = array(
'2' => 7,
'3' => 4,
'1' => 2,
);
$keySorted = array_keys($sorted);
usort($records, function ($a, $b) use ($keySorted) {
$pos_a = array_search($a->id, $keySorted);
$pos_b = array_search($b->id, $keySorted);
return $pos_a - $pos_b;
});
var_dump($records);
Here, I have created sorting of array and add to your array of object using current() and key() is from php.
$i = 0;
while ($value = current($sorted)) {
$key = key($sorted); // get key from array 2
$records[i]->array('id' => $key); // set key to array of object
next($array);
$i++;
}
I hope this may help you.
Code: (Demo)
$records = [(object)['id' => 1], (object)['id' => 2], (object)['id' => 3]];
$sorted = ['2' => 7, '3' => 4, '1' => 2];
$tempArr = array();
foreach ($records as $value) {
$tempArr[$value->id] = $value;
}
$resultArr = array_values(array_replace($sorted, $tempArr));
var_export($resultArr);
Output:
array (
0 =>
stdClass::__set_state(array(
'id' => 2,
)),
1 =>
stdClass::__set_state(array(
'id' => 3,
)),
2 =>
stdClass::__set_state(array(
'id' => 1,
)),
)

PHP finding same record in array

I would like to detect same records and then change quantity of the one record and delete the others. For example, given the following array:
'Cart' => [
(int) 0 => [
'size' => '38',
'code' => '5',
'qn' => (int) 1
],
(int) 1 => [
'size' => '37',
'code' => '5',
'qn' => (int) 1
],
(int) 2 => [
'size' => '37',
'code' => '5',
'qn' => (int) 1
]
],
i would like to print:
'Cart' => [
(int) 0 => [
'size' => '38',
'code' => '5',
'qn' => (int) 1
],
(int) 1 => [
'size' => '37',
'code' => '5',
'qn' => (int) 2
]
],
It looks to me that you're trying to sum quantities (qn) on duplicate sizes (size) and codes (code). One way to achieve this is by looping through the array containing the cart items and building out a new array. I suggest reading about PHP arrays and array_key_exists to learn more as they're used below:
<?php
$arr = [
['size' => '38', 'code' => 5, 'qn' => 1],
['size' => '37', 'code' => 5, 'qn' => 1],
['size' => '37', 'code' => 5, 'qn' => 1],
['size' => '37', 'code' => 4, 'qn' => 1],
];
$newArr = [];
foreach ($arr as $value) {
$key = $value['size'] . ':' . $value['code'];
if (array_key_exists($key, $newArr)) {
$newArr[$key]['qn'] += $value['qn'];
continue;
}
$newArr[$key] = $value;
}
// Resets keys
$newArr = array_values($newArr);
print_r($newArr);
I dont know it is enough for your problem, but try function array_unique
Iterate your array and use array_diff on each subarray.
If the returned array doesn't contain neither size nor code, add the two qn
The function array_unique() works for single dimension array. To find unique elements from multi-dimension array, we need to do a little modification.
Try this:
$array = array_map("serialize", $array);
$output = array_map("unserialize", array_unique($array));
If you want to follow another approach, use this as a reference: Create multidimensional array unique
Please go through following code.
$result = [
0=> ['size' => '38',
'code' => '5',
'qn' => 1
],
1=> ['size' => '37',
'code' => '5',
'qn' => 1
],
2=> ['size' => '37',
'code' => '5',
'qn' => 1
]
];
$finalArr = [];
foreach($result as $k => $v) {
$flag = 0;
foreach($finalArr as $kc => $vc){
if($v['size']==$vc['size'] && $v['code']==$vc['code']){
$flag = 1;
$finalArr[$kc]['qn'] = $finalArr[$kc]['qn'] + 1;
break;
}
}
if($flag==0){
$finalArr[] =
[
'size' => $v['size'],
'code' => $v['code'],
'qn' => 1
];
}
}
echo "<pre>";
print_r($finalArr);
The code is tested against your question and i have explained the code. This gives you solution for any number of arrays and with similar array elements with quantity(qn) incremented as you wanted:
<?php
//Compare the 1st and 2nd array
//Compare the 2st and 3rd array
// and so on
function compare($arr1 = array(), $arr2 = array()) {
$result = array_diff($arr1, $arr2);
return $result;
}
$cart = array(
0 => array('size' => 38, 'code' => 5, 'qn' => 1),
1 => array('size' => 37, 'code' => 5, 'qn' => 1),
2 => array('size' => 37, 'code' => 5, 'qn' => 1),
);
$j = 1;
$cart_total_count = count($cart);//Gives the count of your cart
$final_cart = array();//Final array with qn incremented
for($i=0;$i<$cart_total_count; $i++) {
if (!empty($cart[$i+1])) {//If 2nd array is not present then stop the comparision
if (empty(compare($cart[$i], $cart[$i+1]))){
$j++;
$cart[$i]['qn'] = $j;
$final_cart = $cart[$i];
}
}
}var_dump($final_cart);
//Output
//1. If 2 array are same
//array(3) { ["size"]=> int(37) ["code"]=> int(5) ["qn"]=> int(2) }
//2. If no array are same
//array(0) { }?>

Categories