php sum values based on same same ids in an array - php

I want to sum input['amount'] in given array only if input['ids'] are same. Please tell any best solution. Thanks
$input = [
'ids' => [1, 2, 3, 1],
'amount' => [50, 100, null, 100]
];
$result = [];
foreach ($input['ids'] as $key => $value) {
echo $key . ' = ' . $value . '<br>';
if($key == $key) {
$result['amount'] += $input['amount'][$key];
}
}
// I want this result form input array. thanks
$result = [
'ids' => [1, 2, 3],
'amount' => [150, 100, null]
];

// new array, ids => amount
$ids = array_unique($input['ids']);
// intialise to 0
foreach($ids as $id) {
$tempMap[$id] = 0;
}
// sum
foreach(array_values($input['amount']) as $i => $amount) {
if (is_null($amount)) {
$tempMap[ $input['ids'][$i] ] = $amount;
} else {
$tempMap[ $input['ids'][$i] ] += $amount;
}
}
$result['ids'] = array_keys($tempMap);
$result['amount'] = array_values($tempMap);

Use an associative array to hold the sums.
$sums = [];
foreach ($input['ids'] AS $index => $id) { // loop over the IDs
if ($input['amount'][$index] !== null) { // check if the corresponding amount is not null
$sums[$id] += $input['amount'][$index]; // Add it to the associative array that's keyed by ID
}
}
$result = [];
$result['ids'] = array_unique($input['ids']); // find all the different IDs
$result['amount'] = array_map(function($id) use($sums) {
return $sums[$id] ?? null; // for each ID, return the sum, or null if all the corresponding amounts were null
}, $result['ids']);

Related

How to sum column value or multiple values in multi-dimensional array?

How can I add all the columnar values by associative key? Note that key sets are dynamic and some key value is more than one.
Example array :
$myArray = array(
["apple" => 2,"orange" => 1,"lemon" => 4,"grape" => 5],
["apple" => 5,"orange" => 0,"lemon" => 3,"grape" => 2],
["apple" => 3,"orange" => 0,"lemon" => 1,"grape" => 3],
);
With single key value I can sum the column value easily with the code below.
$sumArray = array();
foreach ($myArray as $k => $subArray)
{
foreach ($subArray as $id => $value)
{
if (array_key_exists($id, $sumArray))
{
$sumArray[$id] += $value;
} else {
$sumArray[$id] = $value;
}
}
}
echo json_encode($sumArray);
the result will be like these:
{"apple":10,"orange":1,"lemon":8,"grape":10}
For multiple key values the code above is not working. How to sum column values if key value is more than one?
Example array:
$myArraymulti = array(
["apple" => 2,"orange" => 1,"lemon" => [4, 2],"grape" => 5],
["apple" => 5,"orange" => [0, 2],"lemon" => 3,"grape" => 2],
["apple" => 3,"orange" => 0,"lemon" => 1,"grape" => [3, 8]],
);
Desired result:
{"apple":10,"orange":3,"lemon":10,"grape":18}
Check if the value is an array. If it is, use the sum of the elements instead of the value itself when adding to the associative array.
foreach ($myArray as $k => $subArray)
{
foreach ($subArray as $id => $value)
{
if (is_array($value)) {
$value_to_add = array_sum($value);
} else {
$value_to_add = $value;
}
if (array_key_exists($id, $sumArray))
{
$sumArray[$id] += $value_to_add;
} else {
$sumArray[$id] = $value_to_add;
}
}
}
I suggest you fix your data structure, though. You should just make every value an array, rather than mixing singletons and arrays, so you don't have to use conditionals in all the code that processes the data.
$keys = [];
forEach($myArraymulti as $array){
$keys = array_merge(array_keys($array), $keys);
}
$res = [];
forEach(array_unique($keys) as $key){
forEach($myArraymulti as $array){
if(isset($array[$key])){
$res[$key] = (isset($res[$key]) ? $res[$key] : 0) +
(is_array($array[$key]) ? array_sum($array[$key]) : $array[$key]);
}
}
}
$res = json_encode($res));

Shuffle only same value associative array in PHP

My array is
$rank = [
'20' => 1,
'30' => 1,
'40' => 2,
'50' => 2,
'60' =>3,
];
expected op
$rank = ['30' => 1,'20' => 1,'50' => 2,'40' => 2,'60' =>3];
I want ranking random means only rank 1(value) should shuffle, later rank 2 should shuffle. later 3 and so on.. how to do it this in PHP?
function shuffle_array($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = array();
foreach ($keys as $key) {
$random[$key] = $list[$key];
}
return $random;
}
echo "<pre>"; print_r(shuffle_array($rank));
First step can be to collect all values(say roll numbers) in an array( say a set) grouped by ranks nicely.
Now, get all the unique ranks from your array.
Sort the ranks(skip this step and just run a for loop starting from 1 if ranks are sequential).
Loop over this unique ranks and get all roll numbers according to the rank in hand.
Shuffle() them and add all of them to your result.
Snippet:
<?php
function getRandomizedSortedData($ranks){
$rank_set = [];
foreach($ranks as $roll_no => $rank){
if(!isset($rank_set[ $rank ])){
$rank_set[$rank] = [];
}
$rank_set[$rank][] = $roll_no;
}
$unique_ranks = array_unique($ranks);
sort($unique_ranks);
$result = [];
foreach($unique_ranks as $rank){
$roll_nos = $rank_set[$rank];
shuffle($roll_nos);
foreach($roll_nos as $roll_no){
$result[$roll_no] = $rank;
}
}
return $result;
}
Demo: http://sandbox.onlinephpfunctions.com/code/86c0ead227a06dda5c048dc9316c53788838bd65
you can use php function array_filter():
$rank = [
'20' => 1,
'30' => 2,
'40' => 3,
'50' => 2,
'60' => 1,
];
function filterRank1($value) {
return $value === 1;
}
function filterRank2($value) {
return $value === 2;
}
...
$rank1 = array_filter($rank, 'filterRank1');
$rank2 = array_filter($rank, 'filterRank2');
...

Array parsing php

How to get from array:
$a = [
'color' => ['red', 'blue', ....∞],
'size' => ['10 -12 ', '12 -14', ....∞],
.....∞
];
such an array
$b = [
['color' => 'red', 'size' => '10 -12 '],
['color' => 'blue', 'size' => '10 -12 '],
['color' => 'red', 'size' => '12 -14 '],
['color' => 'blue', 'size' => '12 -14 '],
];
keys and values can be any number,
the names of keys and values can be different
php cross join
I tried to do it, but it's limited
foreach($a['color'] as $k1 => $v1){
foreach($a['size'] as $k2 => $v2){
$d[] = ['color' => $v1, 'size' => $v2];
}
}
no one here can solve it, apparently it's difficult, I found a solution
Solution 1
function cross($array)
{
$result = [];
$current = array_splice($array, -1);
foreach ($current as $key => $values) {
foreach ( $values as $value) {
if (empty($array)) {
array_push($result, [$key => $value]);
} else {
foreach (cross($array) as $temp) {
array_push($result, array_merge([$key => $value], $temp));
}
}
}
}
return $result;
}
print_r(cross($a));
Solution 2
function cartesian($input) {
$result = array();
while (list($key, $values) = each($input)) {
// If a sub-array is empty, it doesn't affect the cartesian product
if (empty($values)) {
continue;
}
// Seeding the product array with the values from the first sub-array
if (empty($result)) {
foreach($values as $value) {
$result[] = array($key => $value);
}
}
else {
// Second and subsequent input sub-arrays work like this:
// 1. In each existing array inside $product, add an item with
// key == $key and value == first item in input sub-array
// 2. Then, for each remaining item in current input sub-array,
// add a copy of each existing array inside $product with
// key == $key and value == first item of input sub-array
// Store all items to be added to $product here; adding them
// inside the foreach will result in an infinite loop
$append = array();
foreach($result as &$product) {
// Do step 1 above. array_shift is not the most efficient, but
// it allows us to iterate over the rest of the items with a
// simple foreach, making the code short and easy to read.
$product[$key] = array_shift($values);
// $product is by reference (that's why the key we added above
// will appear in the end result), so make a copy of it here
$copy = $product;
// Do step 2 above.
foreach($values as $item) {
$copy[$key] = $item;
$append[] = $copy;
}
// Undo the side effecst of array_shift
array_unshift($values, $product[$key]);
}
// Out of the foreach, we can add to $results now
$result = array_merge($result, $append);
}
}
return $result;
}
Is this what you are trying to achieve? Note that for it to work correctly, the number of parameters for color and size must be the same!
<?php
$b = ['color' => ['red', 'blue', 'yellow'],'size' => ['10 -12 ', '12 -14', '12-16']];
for ($counter=0; $counter < sizeof($b['color']) ; $counter++) {
$d[$counter]['color'] = $b['color'][$counter];
$d[$counter]['size'] = $b['size'][$counter];
}
echo "<pre>";
print_r($d);
?>

Splitting a Associative Array Based off if Condition of Value

I'm combining an array based off a MySQL Query:
$newskus = array();
$newqtys = array();
$sql1 = $db->query("//QUERY//");
while($row = $sql1->fetch_assoc()) {
$newskus[] = $row['SKU'];
$newqtys[] = $row['Quantity'];
}
$newskusandqtys = array_combine($newskus, $newqtys);
This gives me an associative array like so:
Array
(
[Product 1] => -1
[Product 2] => 0
[Product 3] => 3
)
I'm looking to split this array based off the condition of the integer value.
That is, if the value is above 0, it'll put the contents into a variable $newqtysabovezero
Ending with an expected output of
Array
(
[Product 3] => 3
)
And the other way around, if the value is greater than or equal to 0, put this into an array variable $newqtysbelowzero with an expected output of
Array
(
[Product 1] => -1
[Product 2] => 0
)
I'm able to do this with a numerical array, but it of course is not passing the key:
foreach( $newqtys as $item ) {
if ( $item > '0' ) {
$newqtysabovezero[] = $item;
} elseif ( $item <= '0') {
$newqtysbelowzero[] = $item;
}
}
How would I modify this to get my expected output?
Here is one way:
foreach( $newqtys as $key => $item ) {
if ( $item > '0' ) {
$newqtysabovezero[$key] = $item;
} elseif ( $item <= '0') {
$newqtysbelowzero[$key] = $item;
}
}
And here is a method using array_filter():
$in = array(
'Product 1' => -1,
'Product 2' => 0,
'Product 3' => 3
);
function at_and_below($v) {
return $v <= 0;
}
function above($v) {
return $v > 0;
}
$newqtysabovezero = array_filter($in, 'above');
$newqtysbelowzero = array_filter($in, 'at_and_below');
At first, to get all values from the 'Quantity' field as integers you should cast them to integer type:
...
while($row = $sql1->fetch_assoc()) {
$newskus[] = $row['SKU'];
$newqtys[] = (int) $row['Quantity'];
}
$newskusandqtys = array_combine($newskus, $newqtys);
Then, you can easily separate values which are greater than OR equal/less than 0:
foreach (newskusandqtys as $k => $item) {
if ($item > 0) {
$newqtysabovezero[$k] = $item;
} else {
$newqtysbelowzero[$k] = $item;
}
}
You can skip the array_combine part, and just read the values into the final arrays as you fetch them.
while($row = $sql1->fetch_assoc()) {
if ($row['Quantity'] > 0) {
$newqtysabovezero[$row['SKU']] = $row['Quantity'];
} else {
$newqtysbelowzero[$row['SKU']] = $row['Quantity'];
}
}

Joining rows from two 2d arrays where a common column value is found

I have two arrays that I would like to join into one. Both arrays have a common key=>value and I would like to insert the values of one array to the other so that I to create one array.
$array1 = [
['ID' => 123456, 'Key' => 1000, 'value' => 123.45],
['ID' => 789012, 'Key' => 1001, 'value' => 56748.17],
];
$array2 = [
['Key' => 1000, 'description' => 'desc1'],
['Key' => 1001, 'description' => 'desc2'],
];
I would like to join Array2 with Array1 so that the resulting Array is as follows:
array (
0 =>
array (
'ID' => 123456,
'Key' => 1000,
'value' => 123.45,
'description' => 'desc1',
),
1 =>
array (
'ID' => 789012,
'Key' => 1001,
'value' => 56748.17,
'description' => 'desc2',
),
)
So the arrays have been joined using the [Key] value as the, well, key. I've looked at array_merge and other function but I can't seem to get these two arrays to "merge" properly.
try this, its linear
$keyval = array();
foreach($array1 as $item)$keyval[$item['Key']] = $item['value'];
foreach($array2 as $key=>$item)$array2[$key]['description'] = isset($keyval[$item['Key']]) ? $keyval[$item['Key']] : '';
You would have to do something like
$result = array();
foreach ($a1 as $v1)
{
foreach ($a2 as $k2 => $v2)
{
if ($v1['Key'] === $v2['Key'])
{
$result[] = array_merge($v1, $v2);
unset($a2[$k2]);
break;
}
}
}
Version with for loops
$result = array();
$c_a1 = count($a1);
$c_a2 = count($a2);
for ($i = 0; $i < $c_a1; $i++)
{
for ($j = 0; $j < $c_a2; $j++)
{
if ($a1[$i]['Key'] === $a2[$j]['Key'])
{
$result[] = array_merge($a1[$i], $a2[$j]);
unset($a2[$j]);
$c_a2--;
break;
}
}
}
This is my approach:
$temp_ array = array_fill_keys (array_map(create_function('$a', 'return $a["Key"];'), $array_1) , $array_1);
$result = array();
foreach ($array_2 as $item) {
if (isset($temp_array[$item['Key']])) {
$result[] = array_merge($item, $temp_array[$item['Key']]);
}
}
I have elaborated more in the code above, and reached this improved version:
function array_merge_items_by_common_key_value($key, $array_1, $array_2)
{
$result = array();
$temp_ array = array_fill_keys(array_map(create_function('$a', 'return $a["' . $key . '"];'), $array_1) , $array_1);
foreach ($array_2 as $item)
{
$result[$item[$key]] = isset($temp_array[$item[$key]]) ? array_merge($item, $temp_array[$item[$key]]) : $item;
}
return array_values(array_merge($result, array_diff_key($array_1, $result)));
}
$merged_arrays = array_merge_items_by_common_key_value('Key', $temp_array, $array_2);
First, a temporary array is created: it is equal to $array_1, but its keys are the values to be matched.
Then, $array_2 is looped. When a match is found, the merge is done. If there is no match, then the $array_2 value is maintained, untouched.
Finally, those values in the $array_1 which were not matched, are also appended to the resulting array.
So, no item of both $array_1 or $array_2 is lost, while the matched items are merged.
#radashk's solution will work if you can always guarantee that $array1[$i] corresponds to $array2[$i]. From my reading of the question, that's not guaranteed, but instead you want to make sure that $array1[$i]['Key'] == $array2[$j]['Key'], and combine elements where those Keys match.
There may be a more elegant solution, but I would do it like this:
// builds up new $tmpArray, using the Key as the index
$tmpArray = array();
foreach($array1 as $innerArray1){
$tmpArray[$innerArray1['Key']] = $innerArray1;
}
//Merges the values from $array2 into $tmpArray
foreach($array2 as $innerArray2) {
if (isset($tmpArray[$innerArray2['Key']])) {
$tmpArray[$innerArray2['Key']] = array_merge($tmpArray[$innerArray2['Key']], $innerArray2);
}else{
$tmpArray[$innerArray2['Key']] = $innerArray2;
}
}
Use temporary first level keys to swiftly identify matching Key values between the two arrays. When an array2 row qualifies for merger with the first, use the union-assignment operator (+=). Call array_value() after looping if you don't want to preserve the temporary keys.
Code: (Demo)
$result = array_column($array1, null, 'Key');
foreach ($array2 as $row) {
if (isset($result[$row['Key']])) {
$result[$row['Key']] += $row;
}
}
var_export(array_values($result));

Categories