I have 2 similar arrays:
$array_a = array(
array(
"id" => 1,
"merchant_reference" => "12345"
),
array(
"id" => 2,
"merchant_reference" => "67890"
)
);
$array_b = array(
array(
"id" => 1,
"merchant_reference" => "12345"
),
array(
"id" => 2,
"merchant_reference" => "67890"
),
array(
"id" => 3,
"merchant_reference" => "12345"
)
);
The only difference is $array_b has an additional item. I'd like to output a new array that counts the total keys of $array_a and removes all keys in $array_b up to that count. And, just leave the 3rd item in $array_b.
I've tried:
function compare_arrays($array1, $array2) {
$array1_count = count($array1);
$array2_count = count($array2);
$array2_count = $array2_count - $array1_count;
$array2 = array_slice($array2, $array1_count, $array2_count);
return $array2;
}
But, what's the best way to do this?
As per the discussion under comment, your code is fine, just an additional conditional check which will improve execution time in case no addition after 12 pm is found.
function compare_arrays($array1, $array2) {
$array1_count = count($array1);
$array2_count = count($array2);
$array2_count = $array2_count - $array1_count;
if($array2_count > 0){
return $array2 = array_slice($array2, $array1_count, $array2_count);
}
return $array1;
}
Related
I would like to extract all the possible variations of the data in the following array ($OriginalData) to how it is laid out in the 2nd array ($Variations).
In this instance, there are 3 questions but this figure is variable. Question 1 has 3 options, question 2 has 5 options and question 3 has 2 options.
I need to get an array of objects which contain every possible answer combination of the 3 questions. In this case I believe there should be 30 possible combinations. I have provided the expected output (for the first 3 combinations) in the $Variations array.
Any help greatly appreciated!
$OriginalData = array();
$OriginalData[] = (object) array(
'ID'=>51,
'Options'=>array(
array('OptionID'=>27396,'Surcharge'=>50),
array('OptionID'=>27397,'Surcharge'=>40),
array('OptionID'=>27398,'Surcharge'=>45),
)
);
$OriginalData[] = (object) array(
'ID'=>52,
'Options'=>array(
array('OptionID'=>27383,'Surcharge'=>5),
array('OptionID'=>27384,'Surcharge'=>5),
array('OptionID'=>27385,'Surcharge'=>5),
array('OptionID'=>27386,'Surcharge'=>5),
array('OptionID'=>27387,'Surcharge'=>5),
)
);
$OriginalData[] = (object) array(
'ID'=>53,
'Options'=>array(
array('OptionID'=>27343,'Surcharge'=>12),
array('OptionID'=>27344,'Surcharge'=>15),
)
);
print_r($OriginalData);
$Variations[0]['Options'][51] = (object) array('OptionID'=>27396,'Surcharge'=>50);
$Variations[0]['Options'][52] = (object) array('OptionID'=>27383,'Surcharge'=>5);
$Variations[0]['Options'][53] = (object) array('OptionID'=>27343,'Surcharge'=>12);
$Variations[0]['Summary'] = (object) array('TotalSurcharge'=>67);
$Variations[1]['Options'][51] = (object) array('OptionID'=>27397,'Surcharge'=>40);
$Variations[1]['Options'][52] = (object) array('OptionID'=>27383,'Surcharge'=>5);
$Variations[1]['Options'][53] = (object) array('OptionID'=>27343,'Surcharge'=>12);
$Variations[1]['Summary'] = (object) array('TotalSurcharge'=>57);
$Variations[2]['Options'][51] = (object) array('OptionID'=>27398,'Surcharge'=>45);
$Variations[2]['Options'][52] = (object) array('OptionID'=>27383,'Surcharge'=>5);
$Variations[2]['Options'][53] = (object) array('OptionID'=>27343,'Surcharge'=>12);
$Variations[2]['Summary'] = (object) array('TotalSurcharge'=>62);
print_r($Variations);
Here is a solution:
$OriginalData = array();
$OriginalData[] = (object) array(
'ID' => 51,
'Options' => array(
array('OptionID' => 27396, 'Surcharge' => 50),
array('OptionID' => 27397, 'Surcharge' => 40),
array('OptionID' => 27398, 'Surcharge' => 45),
)
);
$OriginalData[] = (object) array(
'ID' => 52,
'Options' => array(
array('OptionID' => 27383, 'Surcharge' => 5),
array('OptionID' => 27384, 'Surcharge' => 5),
array('OptionID' => 27385, 'Surcharge' => 5),
array('OptionID' => 27386, 'Surcharge' => 5),
array('OptionID' => 27387, 'Surcharge' => 5),
)
);
$OriginalData[] = (object) array(
'ID' => 53,
'Options' => array(
array('OptionID' => 27343, 'Surcharge' => 12),
array('OptionID' => 27344, 'Surcharge' => 15),
)
);
$variations = array();
$counts = array();
$combinations = [[]];
$length = count($OriginalData);
for ($i = 0; $i < $length; $i++) {
$counts[] = range(0, count($OriginalData[$i]->Options) - 1);
}
for ($count = 0; $count < $length; $count++) {
$tmp = [];
foreach ($combinations as $v1) {
foreach ($counts[$count] as $v2)
$tmp[] = array_merge($v1, [$v2]);
}
$combinations = $tmp;
}
$x = 0;
foreach ($combinations as $c) {
$totalsurcharge = 0;
for ($i = 0; $i < $length; $i++) {
$Variations[$x]['Options'][$OriginalData[$i]->ID] = (object) $OriginalData[$i]->Options[$c[$i]];
$totalsurcharge += $OriginalData[$i]->Options[$c[$i]]['Surcharge'];
}
$Variations[$x]['Summary'] = (object) array('TotalSurcharge' => $totalsurcharge);
$x++;
}
var_dump($Variations);
Consider two simple arrays:
<?php
$array1 = array(
'blue' => 5,
'green' => array(
'square' => 10,
'sphere' => 0.5,
'triangle' => 3
),
'red' => array(
'circle' => 1000,
),
'black' => 4,
);
$array2 = array(
'blue' => 1,
'green' => array(
'square' => 11,
'circle' => 5,
),
'purple' => 10,
'yellow' => array(
'triangle' => 4
),
'black' => array(
'circle' => 6,
),
);
I need to mathmatically add together in a recursive way, each value from each $array1 and $array2.
Preserve keys
Where a key does not exist in $array1 but does exist in $array2, the final array would simply contain the value of $array2 (and the other way around as well)
Where they exist in both, the numeric values would be added +
Non-numeric values wouldn't be touched
If a value on $array1 points to another sub-array, and in $array2 it points to a value, the end value would result in that key containing a subarray that contains the values from $array1 plus a new key/value using the parent name and it's value (see black in the example)
Should be able to work at virtually unlimited nesting
To clarify, e.g. if we said
<?php
$final = array_merge_special($array1, $array2);
// We would end up with, if you var_export()'d final, something like:
// (Note: Hope I didn't make mistakes in this or it will be confusing,
// so expect mild human error)
$final = array(
'blue' => 6, // 5+1
'green' => array(
'square' => 21, // (10+11)
'sphere' => 0.5, // only in $array1
'triangle' => 3 // only in $array1
'circle' => 5, // only in $array2
),
'purple' => 10, // only in $array2
'yellow' => array( // only in $array2
'triangle' => 4
),
'red' => array( // only in $array1
'circle' => 1000,
),
'black' => array(
'circle' => 6, // untouched, while $black is present in both, the $array1 value does not have a 'circle' key, and is actually only a key/value (see below)
'black' => 4, // the key/value from $array1 that was not a subarray, even though it was a subarray in $array2
),
);
This seems outragously daunting to me. I know I could loop over one array and get easily recursively add the values, and I have this working (somewhat), but it's when I get into special rules (such as ones for black) that I can't even imagine how broken code would look. There has to be a way to do this would looping over each array individually and unset()'ing values to merge?
You would use array_walk_recursive (see: See php Manual here) and possibly array_merge_recursive. I'd have to think it through further to get the full picture.
OK, decided that this wouldn't work! Array_walk_recursive doesn't pass keys that hold arrays to the function. This problem kept flowing aroung in my brain, so I just had to write a function to do it! Here it is:
function dosum($arin) {
$arout = array();
foreach ($arin as $key1 => $item1) {
$total = 0;
if(is_array($item1)) {
foreach($item1 as $key2 => $item2) {
if(is_numeric($key2))
$total += $item2;
else
if(is_array($item2))
$arout[$key1] = dosum(array($key2 => $item2));
else
$arout[$key1][$key2] =$item2;
}
if($total)
if(isset($arout[$key1]))
$arout[$key1][$key1] = $total;
else
$arout[$key1] = $total;
}
else
$arout[$key1] = $item1;
}
return $arout;
}
For the 2 arrays given, you would use it like this:
print_r(dosum(array_merge_recursive($array1, $array2)));
I use this code :
$new = array(
"123" => "a",
"456" => "b"
);
$old = array(
"123" => "a",
"456" => "b"
);
then the $new array become like this:
$new = array(
"456" => "b",
"123" => "c",
"789" => "e"
);
as you see the count of $new array increased and the order of elements changed and the value at key 123 also changed. I need to compare the $new array against the $old array and catch only the change made on the value at key 123 without caring about the order and the count of elements. I tried:
$result = array_diff( $new, $old );
print_r( $result );
output :
Array ( [123] => c [789] => e )
UPDATE. quite confusing. now I think we got it
$old = array(
"123" => "a",
"456" => "b"
);
$new = array(
"456" => "b",
"123" => "c", // catch this (element in old array that is changed)
"789" => "e"
);
$new2 = array();
foreach ($new as $key => $new_val)
{
if (isset($old[$key])) // belongs to old array?
{
if ($old[$key] != $new_val) // has changed?
$new2[$key] = $new[$key]; // catch it
}
}
// output $new2:
array (
123 => 'c',
)
You first of all want to have those elements of $new that are changed compared to $old (see array_diff_assoc):
$changed = array_diff_assoc($new, $old);
Of that result you want to have only those elements that have their key in $old (see array_intersect_key):
$result = array_intersect_key($changed, $old);
And that's it. You can wrap that into each other if it helps:
array_intersect_key(array_diff_assoc($new, $old), $old);
Result is:
array(1) {
[123] =>
string(1) "c"
}
Full example (Demo):
$old = array(
"123" => "a",
"456" => "b"
);
$new = array(
"456" => "b",
"123" => "c", // catch only the change made on the value at key 123
"789" => "e"
);
$changed = array_diff_assoc($new, $old);
$result = array_intersect_key($changed, $old);
var_dump($result);
Just a final note: There are many array functions in PHP. It's worth to go through the list and look what is fitting because most often you only need one or two of them to get things like these done.
You use this code for your requirements
<?php
function key_compare_func($key1, $key2)
{
if ($key1 == $key2)
return 0;
else if ($key1 > $key2)
return 1;
else
return -1;
}
$array1 = array('blue' => 1, 'red' => 2, 'green' => 3, 'purple' => 4);
$array2 = array('green' => 5, 'blue' => 6, 'yellow' => 7, 'cyan' => 8);
var_dump(array_intersect_ukey($array1, $array2, 'key_compare_func'));
?>
Problem: Find the sum of the values in 'subtotal' for each 'id' and store the respective sum for each id in an array (or variables).
My sloppy solution at the moment is to run a foreach with multiple if statements inside that count the occurrences. This is adequate for something like 5 ids, but I have to iterate this over 38 ids.
I would like to store the results sequentially in an array if possible.
How can I make it more efficient? Any and all help will be appreciated.
(See my sloppy solution at the end of this for a good chuckle)
Desired Result:
sum of all ID 1 = 10
sum of all ID 2 = 18
sum of all ID 3 = 14
sum of all ID 4 = 4
sum of all ID 5 = 3
Array Code for Manipulation
$someArray = array(
array(
'id'=> 1,
'subtotal'=> 5),
array(
'id'=> 1,
'subtotal'=> 5),
array(
'id'=> 2,
'subtotal'=> 6),
array(
'id'=> 2,
'subtotal'=> 6),
array(
'id'=> 2,
'subtotal'=> 6),
array(
'id'=> 3,
'subtotal'=> 7),
array(
'id'=> 3,
'subtotal'=> 7),
array(
'id'=> 4,
'subtotal'=> 2),
array(
'id'=> 4,
'subtotal'=> 2),
array(
'id'=> 5,
'subtotal'=> 3),
);
Sloppy Solution
$sum_id_1 = 0;
$sum_id_2 = 0;
$sum_id_3 = 0;
$sum_id_4 = 0;
$sum_id_5 = 0;
foreach ($someArray as $k) {
if ($k['id'] == 1) {
$sum_id_1 += $k['subtotal'];
}
if ($k['id'] == 2) {
$sum_id_2 += $k['subtotal'];
}
if ($k['id'] == 3) {
$sum_id_3 += $k['subtotal'];
}
if ($k['id'] == 4) {
$sum_id_4 += $k['subtotal'];
}
if ($k['id'] == 5) {
$sum_id_5 += $k['subtotal'];
}
}
Sloppy Solution Output (on echo)
10
18
14
4
3
$sum = array_reduce($someArray, function($result, $item) {
if (!isset($result[$item['id']])) $result[$item['id']] = 0;
$result[$item['id']] += $item['subtotal'];
return $result;
}, array());
var_dump($sum); // array(5) { [1]=> int(10) [2]=> int(18) [3]=> int(14) [4]=> int(4) [5]=> int(3) }
For PHP <= 5.3 perform the counting in loop manually:
$sum = array();
foreach ($someArray as $item) {
if (!isset($sum[$item['id']])) $sum[$item['id']] = 0;
$sum[$item['id']] += $item['subtotal'];
}
$arr3 = array (
"0" => array ( "001" => 10 ),
"1" => array ( "005" => 20 ),
"2" => array ( "001" => 30 ),
"3" => array ( "003" => 20 ),
"4" => array ( "005" => 80 ),
"5" => array ( "001" => 90 ),
"6" => array ( "003" => 20 ),
"7" => array ( "006" => 80 ),
"8" => array ( "006" => 90 )
) ;
array (size=4)
0 =>
array (size=1)
'001' => int 130
1 =>
array (size=1)
'005' => int 100
2 =>
array (size=1)
'003' => int 40
3 =>
array (size=1)
'006' => int 170
$outer_array = array();
$unique_array = array();
$inner_array = array();
foreach($arr3 as $key => $value)
{
$item = key($value);
if(!in_array(key($value), $unique_array))
{
array_push($unique_array, $item);
$inner_array[key($value)] = $value[$item];
$outer_array[$item][$item] = $value[$item];
}else{
$inner_array[key($value)] = $value[$item] + $inner_array[$item];
$outer_array[$item][$item] = $inner_array[$item];
}
}
var_dump(array_values($outer_array));
if you want to sum up all the values with the same key.namely, the above result is what you hope.so my answer is approaching……that is all, wish will help somebody encountering the same situation about this question!
$a = array(
0 => array( 'one' => 1, 'two' => 2 ),
1 => array( 'one' => 3, 'two' => 4 ),
2 => array( 'one' => 5, 'two' => 2 )
);
$c = count( $a );
$r = array();
for ( $i = 0; $i < $c; $i++ )
{
if ( $a[$i]['two'] == 2 )
$r[] = $a[$i];
}
Is there a cleaner way then to do all of the above?
Have you tried using array_filter()?
$r = array_filter($a, function($var) {
return ($var['two'] === 2);
});
The output of the above is slightly different than your original code:
Yours:
array(
0 => array('one' => 1, 'two' => 2),
1 => array('one' => 5, 'two' => 2)
)
Using array_filter:
array(
0 => array('one' => 1, 'two' => 2),
2 => array('one' => 5, 'two' => 2) // Note the key is 2, not 1
)
If you need the keys collapsed, you can follow up the array_filter() with array_values() or array_multisort()
You could write a function to do just this and then use array_walk or array_filter but that's about it.
Only way I can see to clean it up more would be to change the original datastructure.