Sum column values but only if specific key exists in same row - php

I need to sum the price values of all rows where the optional check element exists.
Sample data:
[
6254 => [
'check' => 'on',
'quantity' => 2,
'name' => 'Testing product_special One Size',
'total' => 15.9,
'price' => 33.0000,
'totalken' => 33075.9,
],
6255 => [
'quantity' => 1,
'name' => 'Testing card',
'total' => 113.85,
'price' => 33.0000,
'totalken' => 16537.95,
],
6256 => [
'check' => 'on',
'quantity' => 1,
'name' => 'Testing food',
'total' => 113.85,
'price' => 33.0000,
'totalken' => 16537.95,
],
]
I tried array_sum(array_column($value, 'price')) but this sums all price values regardless of the check value.
Expected result: 66

I would use array_reduce in this case.
array_reduce loops through the array and uses a callback function to reduce array to a single value.
<?php
$totalPrice = array_reduce($myArray, function ($accumulator, $item) {
// I'm checking 'check' key only here, you can test for 'on' value if needed
if (isset($item['check'])) {
$accumulator += $item['price'];
}
return $accumulator;
});

You can simply filter the array based on condition by using array_filter() function of php.
You can see the usage of array_filter() here.
Here is my solution for you if you want to use condition.
$filteredByCheck = array_filter($value, function ($val){
return isset($val['check']);
});
$total = array_sum(array_column($filteredByCheck, 'price'));

The quickest method would be just to loop over the array and maintain a sum, use ?? '' to default it to blank if not set...
$total = 0;
foreach ($value as $element ) {
if ( ($element['check'] ?? '') == "on" ) {
$total += $element['price'];
}
}

#aliirfaan's implementation of array_reduce() can be modernized and compacted as the following snippet.
Code: (Demo)
echo array_reduce(
$array,
fn($result, $row) =>
$result + isset($row['check']) * $row['price']
);
The above uses arrow function syntax which is available since PHP7.4. The mathematics in the return value of the custom function multiplies the price value by the true/false evaluation of isset() on the check column. The boolean value is coerced to an integer automatically when used with arithmetic -- false is zero and true is one. If the coercion is not to your liking, you can explicitly cast the boolean value using (int) immediately before isset().

Related

Detect if array of objects within an object has duplicate names

I'm looking for a smart way to find out if my array of objects within an object has multiple name values or not to do a validation since it's only allowed to have one array name per inner array:
$elements = [];
$elements[18][20] = [
[
'name' => 'Color',
'value' => 'Red'
],
[
'name' => 'Color',
'value' => 'Green'
],
[
'name' => 'Size',
'value' => 'S'
]
];
$elements[18][21] = [
[
'name' => 'Size',
'value' => 'S'
],
[
'name' => 'Length',
'value' => '20'
],
];
error_log( print_r( $elements, true ) );
So the object 20 for example is invalid because it has 2 colors with the same value. At the end I was hoping to get a result array containing 1 duplicate name. This way I can output them like: "You have at least one duplicate name: Color".
My first idea was to loop over the array and do a second loop. This way it was possible to receive the inner arrays containing the stuff. Now I was able to add every name to another array. After this I was able to use count() and array_intersect() to receive a value of x which showed me if there are duplicates or not.
Now I had a count, but not the actual value to display. Before I use a semi-good solution, I was hoping to get any ideas here how I can make it better!
This loop will generate your expected output:
foreach($elements[18] as $index => $element){
//Get all the elements' names
$column_key = array_column($element, 'name');
//Get the count of all keys in the array
$counted_values = array_count_values($column_key);
//Check if count is > 1
$filtered_array = array_filter($counted_values, fn($i) => $i > 1);
//If the filter is not empty, show the error
if(!empty($filtered_array)){
//get the key name
$repeated_key = array_key_first($filtered_array);
echo "You have at least one duplicate name: {$repeated_key} at index {$index}";
break;
}
}
It relies in the array_count_values function.

Some php coding about array_search with unexpected result

i want to find a key value from a array, if not exist then insert a array set into a array list
If i search blue, it will return Y
But if i search green, return N
$people = array(
0 => array(
'name' => 'John',
'fav_color' => 'green'
),
1=> array(
'name' => 'Samuel',
'fav_color' => 'blue'
)
);
$found_key = array_search('green', array_column($people, 'fav_color'));
if($found_key){
print_r("Y");
}else{
print_r("N");
}
Expect search blue or green return Y
As per note written in the documentation of array_search:
Warning: This function may return Boolean FALSE, but may also return a
non-Boolean value which evaluates to FALSE. Please read the section on
Booleans for more information. Use the === operator for testing the return value of this function.
In Your case, green value has index 0. In if statement 0 means false. To get this rid of this problem, you need to strict type check the value returned by array_search as below.
if ($found_key !== false) { // strict type check
print_r("Y");
} else {
print_r("N");
}
Demo
You can Use in_array() function also.
$people = array(
0 => array(
'name' => 'John',
'fav_color' => 'green'
),
1=> array(
'name' => 'Samuel',
'fav_color' => 'blue'
)
);
$found_key = in_array('green', array_column($people, 'fav_color'));
if($found_key){
print_r("Y");
}else{
print_r("N");
}

Return all values with matching key value pair

Given this:
$array1 = array(
array(
'orderno' => 2,
),
array(
'orderno' => 2,
),,
array(
'orderno' => 1
),
);
How do i get all the arrays with a orderno = 2 leaving out the orderno = 1, I know you could do this via a foreach but I'd like to know if it could be done using a native php method instead of a foreach...
Similar to:
array_search($cmsvalue['custnum'], array_column($custcsvarray, 'custnum'));
but returning all the values not just the first...
If foreach is not native enough, you can use array_filter. The function accepts a callback that is applied to each item. The result is an array that returns all items for which the callback didn't return false.
$array2 = array_filter($array1, function($item) {
return $item['orderno'] == 2;
});

find max value in associative array with condition

$a=2;
$b=6;
$c=7;
$r1=8;
$r2=9;
$r3=6;
$array = array(
array('MIDDAY'=>$a,'RATE'=>$r1),
array('SHORTDAY'=>$b,'RATE'=>$r2),
array('LONGDAY'=>$c,'RATE'=>$r3)
);
I have a array like this and i want this array to process
and want to check whose count is greater like as above LONGDAY=7
then i want this LONGDAY key in one variable and its RATE in other variable
And also want to check if two count is equal then like LONGDAY=7 and MIDDAT=7
then i want to check with RATE whose rate is greater then same
i want this LONGDAY key in one variable and its RATE in other variable (for RATE is greater in this case)
Something along these lines should do it to sort the array according to your rules and take the top result.
$array = array(
array('type' => 'MIDDAY', 'val' => $a, 'rate' => $r1),
array('type' => 'SHORTDAY', 'val' => $b, 'rate' => $r2),
array('type' => 'LONGDAY', 'val' => $c, 'rate' => $r3)
);
usort($array, function ($a, $b) {
if ($a['val'] < $b['val']) return 1;
else if ($a['val'] > $b['val']) return -1;
else return $b['rate'] - $a['rate'];
});
$var1 = $array[0]['type'];
$var2 = $array[0]['rate'];
Note, this uses PHP 5.3+ anonymous function syntax.

php multidimensional array get first date value

I need help once again. I have an array and I need to extract earliest day weight value.
EDIT - EDIT - EDIT
array (
3 =>
array (
'id' => '20110211',
'Date' => '2011-02-11',
'Weight' => '195',
),
4 =>
array (
'id' => '20110213',
'Date' => '2011-02-13',
'Weight' => '160',
),
6 =>
array (
'id' => '20110310',
'Date' => '2011-03-10',
'Weight' => '200',
),
12 =>
array (
'id' => '20110301',
'Date' => '2011-03-01',
'Weight' => '55',
),
21 =>
array (
'id' => '20110215',
'Date' => '2011-02-15',
'Weight' => '120',
),
25 =>
array (
'id' => '20110322',
'Date' => '2011-03-22',
'Weight' => '250',
),
)
I've edited this and this code works:
function sortByDate ($arr1, $arr2)
{
return strcmp($arr1['Date'], $arr2['Date']);
}
// $arr is your array
usort($weight_tracker, 'sortByDate');
$earliest = $weight_tracker[0]['Weight'];
echo $earliest;
But since I have a form on this page which updates the array when array is updated - I got message Fatal error: Cannot use string offset as an array in
EDIT -> I've re-declared this as string, hence the ERROR ! be careful when using global and includes as everything can become a mess ! PHP is forgiving, but that "forgiveness" can cost a lot of time later on... :)
Thanks,
Peter
You could sort the array with a custom callback using usort() and then take the first element.
// $arr is your array
usort($arr, 'sortByDate');
$earliest = $arr[0];
function sortByDate ($arr1, $arr2)
{
return strcmp($arr1['Date'], $arr2['Date']);
}
This is one way of doing it:
function filter_min($a, $b) {
return ($a['Date'] < $b['date']) ? $a : $b;
}
$result = array_reduce($array, 'filter_min');
echo $result['Weight'];
Another way is to simply iterate over the array and find the smallest date.
$smallest = null; // array index of entry with smallest weight.
foreach ($array as $idx => $data) {
if (($data['Weight'] < $array[$smallest]['Weight']) || (is_null($smallest))) {
$smallest = $idx; // found a small weight, so save the index
}
}
echo $array[$smallest]['Date'];
I noticed that the dates are in reverse order with the latest date being pulled in first, and the earliest date last. Will it always be like that? If so, you can do this:
$index = count($array) - 1;
$earliestdate = $array[$index]['Date'];
You could also use array_reverse() to invert the array and make the first element the formerly last element.
If this is being pulled in from MySQL you could also alter the query to ORDER BY 'Date' DESC (or is it ASC that would get you what you want, can't remember)

Categories