I have an array in PHP of this type, resulting from a particular query on a db.
$output = Array
(
[0] => Array
(
'price' => 100
'date' => '2015-07-28'
'total' => 200
'qty' => 2
)
[1] => Array
(
'price' => 80
'date' => '2015-07-28'
'total' => 240
'qty' => 3
)
[2] => Array
(
'price' => 100
'date' => '2015-07-29'
'total' => 300
'qty' => 3
)
[3] => Array
(
'price' => 90
'date' => '2015-07-28'
'total' => 90
'qty' => 1
)
)
I'm trying to sum total and qty based on price key values, obtaining an array that will look like this:
$grouped = Array
(
[0] => Array
(
[price] => 100
[sumtotal] => 500
[sumqty] => 5
)
[1] => Array
(
[price] => 80
[sumtotal] => 240
[sumqty] => 3
)
[2] => Array
(
[price] => 90
[sumtotal] => 90
[sumqty] => 1
)
)
Still cannot find a way to get around this.
Try using simple foreach loop as
$result = array();
foreach ($output as $key => $value) {
$hash = $value['price'];
if (isset($result[$hash])) {
$result[$hash]['price'] = $value['price'];
$result[$hash]['sumtotal'] += $value['total'];
$result[$hash]['sumqty'] += $value['qty'];
} else {
$result[$hash]['price'] = $value['price'];
$result[$hash]['sumtotal'] = $value['total'];
$result[$hash]['sumqty'] = $value['qty'];
}
}
print_r(array_values($result));
Demo
I don't understand, it's the same array without the date.. ?
Edit :
Ok try this
$temp= array();
for($i=0; $i<sizeof($outpout);$i++)
{
if(!isset($temp[$i]))
$temp[$i]=array();
$temp[$i][$outpout[$i]['price']]+=$outpout[$i]['qty']];
}
$res=array();
$count=0;
foreach($temp as $key => $value)
{
$res[$count]['price']=$key;
$res[$count]['qty']=$value;
$res[$count]['total']=$key*$value;
$count++;
}
Okay, here's a simple complete code to solve your problem.
$output=array();//this is your array
$price_index=array();
$final_array=array();
foreach($output as $key=>$value)
{
//first check if price is already in $price_index
if(!isset($price_index[$value["price"]]))
{
$price_index[$value["price"]]=sizeof($price_index);
}
$final_index=$price_index[$value["price"]];
if(isset($final_array[$final_index]))
{
$final_array[$final_index]["total"]+=$value["total"];
$final_array[$final_index]["qty"]+=$value["qty"];
}
else
{
$final_array[$final_index]["total"]=$value["total"];
$final_array[$final_index]["qty"]=$value["qty"];
$final_array[$final_index]["price"]=$value["price"];
}
}
//display our final array
print_r($final_array);
What I did:
iterate through your array
check if the current price has been added to $final_array before, by creating $price_index array that contains price as key and the value is the index of $output array on the first time the price occurred.
now if the price occur again, the $price_index[current price] will be detected that it is already been set before, then we will use the value as the index of our $final_array and add the current total and qty to existing.
then display the array (optional).
Hope it helps. Please don't just copy my code, analyze and understand it mate :)
Related
I want to remove array from multidimentional array using base of ID. I tried using foreach loop. But, It is not working.
Any one help me how to remove this?
Thanks.
=> Array :
Array
(
[0] => Array
(
[id] => 11109
[value] => Yes
[field_id] => 234
)
[1] => Array
(
[id] => 11109
[value] => Yes
[field_id] => 237
)
[2] => Array
(
[id] => 11110
[value] => No
[field_id] => 234
)
[3] => Array
(
[id] => 11110
[value] => No
[field_id] => 237
)
[4] => Array
(
[id] => 11111
[value] => No
[field_id] => 237
)
)
From this array, I want to remove array which
field_id is 234 and value is "No" && field_id is 237 and value is
"No".
field_id is 234 and value is "Yes" && field_id is 237 and value is
"Yes".
So, From this array only ID 11111 array is display otherwise all array remove from current array.
Here is my code using I tried to remove array.
foreach ($collection->getData() as $key => $value) {
if(($value['field_id'] == $ids[0] && $value['value'] == "No")){
echo $value['id'];
// exit;
break;
}
echo $value['field_id'];
echo $value['value'];
if(($value['field_id'] == $ids[1] && $value['value'] == "No")){
print_r($collection->getData()[$key]);
unset($collection->getData()[$key]);
unset($collection->getData()[$key-1]);
}
}
You can create a new Multidimensional array , and copy only the values you want to it .
also , when you use break , you get out of the foreach loop completely , i don't think this is the intended behavior , use continue to skip current iteration and test the next element
Is the function getData() returning a copy of the array or a reference? If is is only a copy the unset($collection->getData()[$key]) won't work.
Better you loop over the array as you do, but store all keys you want to delete in side a other array (e.g. $keysToRemove). When the for-each-loop is finished you start to loop the new array $keysToRemove containing all the keys you want to remove and remove then from array.
$keysToRemove = array();
$data = $collection->getData(); // copy or reference?
foreach ($data as $key => $value) {
if(($value['field_id'] == $ids[0] && $value['value'] == "No")){
echo $value['id'].'<br>';
break; // exit the loop? If you want to jump to the next element use "continue"
}
echo $value['field_id'].'<br>';
echo $value['value'].'<br>';
if(($value['field_id'] == $ids[1] && $value['value'] == "No")){
$keysToRemove[$key] = true;
$keysToRemove[$key-1] = true;
}
}
foreach(array_keys($keysToRemove) as $key){
echo '<p>remove key '.$key.' with content <pre>'.print_r($data[$key], true).'</pre></p>';
unset($data[$key]);
}
echo '<p>Result array is<pre>'.print_r($data, true).'</pre></p>';
So you don't manipulate the array your loop use at the moment.
Based on the comment that mentioned its a Magento Collection. I think, You could filter the ids in collection itself so that those are not fetched as part of the collection you want. Like:
$collection = Mage::getModel('your/model')->getCollection();
$collection->addAttributeToFilter('field_id', array('nin' => array(234, 237)));
OR, following if your model is non-eav entity model
$collection = Mage::getModel('your/model')->getCollection();
$collection->addFieldToFilter('field_id', array('nin' => array(234, 237)));
try this code which remove all array value which value is No
$cart = array(
0 => array
(
'id' => 11109,
'value' => 'Yes',
'field_id' => 234
),
1 => array
(
'id' => 11109,
'value' => 'Yes',
'field_id' => 123
),
2 => array
(
'id' => 11110,
'value' => 'No',
'field_id' => 234
),
3 => array
(
'id' => 11110,
'value' => 'No',
'field_id' => 237
),
4 => array
(
'id' => 11111,
'value' => 'No',
'field_id' => 237
),
);
$found = array();
$i = 0;
foreach ($cart as $key => $data) {
if ($data['field_id'] == 234 && $data['value'] == 'No') {
$found[$i]['id'] = $data['id'];
$found[$i]['value'] = $data['value'];
$found[$i]['field_id'] = $data['field_id'];
$i++;
}
}
echo "<pre>";
print_r($found);
then Output Is:
Array
(
[0] => Array
(
[id] => 11111
[value] => No
[field_id] => 234
)
)
This is a question for all the array specialists out there. I have an multi dimension array with a result as number (can be 0,1 or 2) and need the average for each grouped by parent.
In the example below the calculation would be:
subentry1_sub1 = 2 + 2 = 4 (4/2=2)
subentry1_sub2 = 1 + 1 = 2 (2/2=1)
So what I try to archive in PHP is the following result:
subentry1_sub1 average = 2
subentry1_sub2 average = 1
...
I already tried some solutions from similar questions. But with all the recursive functions I didn't managed to get it aggregated by the last child name (e.g. subentry1_sub1).
Any ideas?
EDIT:
subentry1_sub1 is 2 + 2 because its two times in the array
[entry1] => [subentry1] => [subentry1_sub1] => result
[entry2] => [subentry1] => [subentry1_sub1] => result
Array
(
[entry1] => Array
(
[subentry1] => Array
(
[subentry1_sub1] => Array
(
[value] => abc
[result] => 2
)
[subentry1_sub2] => Array
(
[value] => abc
[result] => 1
)
)
[subentry2] => Array
(
[subentry2_sub1] => Array
(
[value] => abc
[result] => 1
)
[subentry2_sub2] => Array
(
[value] => abc
[result] => 1
)
)
)
[entry2] => Array
(
[subentry1] => Array
(
[subentry1_sub1] => Array
(
[value] => abc
[result] => 2
)
[subentry1_sub2] => Array
(
[value] => abc
[result] => 1
)
)
[subentry2] => Array
(
[subentry2_sub1] => Array
(
[value] => abc
[result] => 1
)
[subentry2_sub2] => Array
(
[value] => abc
[result] => 1
)
)
)
)
Try this code. In this i have created a new array $sum which will add result value of same subentry childs with same key and another array $count which will count the number of times each key repeats
<?php
$data = array('entry1'=>array(
'subentry1'=>
array(
'subentry1_sub1'=>array('value'=>'abc','result'=>2),
'subentry1_sub2'=>array('value'=>'abc','result'=>1)
),
'subentry2'=>
array(
'subentry2_sub1'=>array('value'=>'abc','result'=>1),
'subentry2_sub2'=>array('value'=>'abc','result'=>1)
)
),
'entry2'=>array(
'subentry1'=>
array(
'subentry1_sub1'=>array('value'=>'abc','result'=>2),
'subentry1_sub2'=>array('value'=>'abc','result'=>1)
),
'subentry2'=>
array(
'subentry2_sub1'=>array('value'=>'abc','result'=>1),
'subentry2_sub2'=>array('value'=>'abc','result'=>1)
)
)
);
$sum = array();
$repeat = array();
foreach($data as $input){
foreach($input as $array){
foreach($array as $key=>$value){
if(array_key_exists($key,$sum)){
$repeat[$key] = $repeat[$key]+1;
$sum[$key] = $sum[$key] + $value['result'];
}else{
$repeat[$key] = 1;
$sum[$key] = $value['result'];
}}}}
echo "<pre>";
print_r($sum);
print_r($repeat);
foreach($sum as $key=>$value){
echo $key. ' Average = '. $value/$repeat[$key]."</br>";
}
Output
Array
(
[subentry1_sub1] => 4
[subentry1_sub2] => 2
[subentry2_sub1] => 2
[subentry2_sub2] => 2
)
Array
(
[subentry1_sub1] => 2
[subentry1_sub2] => 2
[subentry2_sub1] => 2
[subentry2_sub2] => 2
)
subentry1_sub1 Average = 2
subentry1_sub2 Average = 1
subentry2_sub1 Average = 1
subentry2_sub2 Average = 1
You can easily calculate avg now
Note : As you mentioned you are counting occurence of subentry1_sub1 etc so i did the same so it will also count whether key result exists or not
I know this is an old thread but im pretty sure there is a much easier way of doing this for anyone who is interested:
If you know the result will always be a number:
foreach($my_array as $entry_name => $entry_data)
{
foreach($entry_data as $sub_name => $sub_data)
{
$sub_results = array_column($sub_data, 'result');
$averages[$entry_name][$sub_name] = array_sum($sub_results)/count($sub_results);
}
}
If its possible the result could be NULL or empty, this will check it and return 'N/A' if there is no valid data to calculate an average from:
foreach($my_array as $entry_name => $entry_data)
{
foreach($entry_data as $sub_name => $sub_data)
{
$sub_results = array_filter(array_column($sub_data, 'result'));
$averages[$entry_name][$sub_name] = (count($sub_results) > 0 ? array_sum($sub_results)/count($sub_results) : 'N/A');
}
}
both of these solutions will give you an averages array that will output the average per subentry per entry.
Try this like,
<?php
$data=array('entry1'=>array(
'subentry1'=>
array(
'subentry1_sub1'=>array('value'=>'abc','result'=>3),
'subentry1_sub2'=>array('value'=>'abc','result'=>3)
),
'subentry2'=>
array(
'subentry2_sub1'=>array('value'=>'abc','result'=>2),
'subentry2_sub2'=>array('value'=>'abc','result'=>8)
)
),
'entry2'=>array(
'subentry1'=>
array(
'subentry1_sub1'=>array('value'=>'abc','result'=>6),
'subentry1_sub2'=>array('value'=>'abc','result'=>6)
),
'subentry2'=>
array(
'subentry2_sub1'=>array('value'=>'abc','result'=>10),
'subentry2_sub2'=>array('value'=>'abc','result'=>12)
)
)
);
foreach($data as $k=>$v){
echo "----------------$k---------------------\n";
if(is_array($v)){
foreach($v as $a=>$b){
if(is_array($b)){
echo $a.' average = ';
$c=array_keys($b);// now get *_sub*
$v1=isset($b[$c[0]]['result']) ? $b[$c[0]]['result'] : '';
$v2=isset($b[$c[1]]['result']) ? $b[$c[1]]['result'] : '';
echo ($v1+$v2)/2;
echo "\n";
}
}
}
}
Online Demo
In the meantime I found a simple working solution myself:
foreach ($data as $level2) {
foreach ($level2 as $level3) {
foreach ($level3 as $keyp => $level4) {
foreach ($level4 as $key => $value) {
if($key == 'result') $stats[$keyp] += $value;
}
}
}
}
With that you get the total for every key in an new array $stats.
But be sure to checkout the solution from user1234, too. It's working great and already includes the calculation of the average.
https://stackoverflow.com/a/39292593/2466703
Below is the array output which shows user data, month wise. I need to get the sum of ACTUAL_HOURS for different resources.
For below, sum of ACTUAL_HOURS for User 1 and User 2 for the month JUL-2015, should be 10 + 20 = 30.
Same goes for AUG-2015 which is 80 + 20 = 100
$user_array output
Array
(
[User 1] => Array
(
[JUL-2015] => Array
(
[SITE_STATUS] => Offshore
[ACTUAL_HOURS] => 10
[PROJECTED_HOURS] => 20
)
[AUG-2015] => Array
(
[SITE_STATUS] => Offshore
[ACTUAL_HOURS] => 80
[PROJECTED_HOURS] => 88
)
)
[User 2] => Array
(
[JUL-2015] => Array
(
[SITE_STATUS] => Offshore
[ACTUAL_HOURS] => 20
[PROJECTED_HOURS] => 0
)
[AUG-2015] => Array
(
[SITE_STATUS] => Offshore
[ACTUAL_HOURS] => 20
[PROJECTED_HOURS] => 0
)
)
)
$project_months output
Array
(
[0] => JUL-2015
[1] => AUG-2015
)
Looping the data like below gives summation but not for User 1
foreach ($user_array as $user_name => $user_data) {
foreach ($project_months as $month) {
}
}
How do I show summation of ACTUAL_HOURS or PROJECTED_HOURS for different resource month wise as shown above ?
You can simply use two foreach loops.
$hoursInMonth = array();
foreach ($users as $user)
{
foreach ($user as $month => $userData) {
$hoursInMonth[$month] += $userData['ACTUAL_HOURS'];
}
}
Considering the $users variable is the array from the question, this yields the following result:
Array
(
[JUL-2015] => 30
[AUG-2015] => 100
)
You could wrap it in a function, so you can easily switch between the desired index.
/**
* #param array $inputArray The input array
* #param string $typeOfHours The desired index
* #return array
*/
function calculateHoursInMonths(array $inputArray, $typeOfHours)
{
$hoursInMonth = array();
foreach ($inputArray as $user)
{
foreach ($user as $month => $userData) {
$hoursInMonth[$month] += $userData[$typeOfHours];
}
}
return $hoursInMonth;
}
Note, this does not take in consideration the Offshore/Onshore state. You can add that by adding a simple if.
You are doing it wrong. There is no need for two nested foreach loops. You just need a for loop to loop through project months and a foreach loop to loop through users array.
You did not shared the array in php code, but I assume you are array is as below:
$array = array(
'User 1' => array(
'JUL-2015' => array(
'SITES_STATUS' => 'Offshore',
'ACTUAL_HOURS' => 10,
'PROJECTED_HOURS' => 20
),
'AUG-2015' => array(
'SITES_STATUS' => 'Offshore',
'ACTUAL_HOURS' => 80,
'PROJECTED_HOURS' => 88
),
),
'User 2' => array(
'JUL-2015' => array(
'SITES_STATUS' => 'Offshore',
'ACTUAL_HOURS' => 20,
'PROJECTED_HOURS' => 0
),
'AUG-2015' => array(
'SITES_STATUS' => 'Offshore',
'ACTUAL_HOURS' => 20,
'PROJECTED_HOURS' => 0
),
),
);
And months are below:
$project_months = array('JUL-2015', 'AUG-2015');
Now to calculate total actual hours for all users for each month, you will need loops like below:
for ($i=0; $i < count($project_months); $i++) {
$totalActualHours = 0;
foreach($array AS $ar) {
$totalActualHours += $ar[$project_months[$i]]['ACTUAL_HOURS'];
}
echo $project_months[$i].': '.$totalActualHours.'<br>';
}
The output of this code when run for ACTUAL_HOURS:
JUL-2015: 30
AUG-2015: 100
Hope this will help.
Suppose I have an array like:
array( [0] => array([item]=>apple [buy]=>50 [sell]=>30)
[1] => array([item]=>lemon [buy]=>50 [sell]=>60)
[2] => array([item]=>banana [buy]=>40 [sell]=>20)
[3] => array([item]=>orange [buy]=>20 [sell]=>30)
)
Currently I am using this script to check which item has the most buyer
function getMax($array, $val)
{
$max = 0;
foreach( $array as $k => $v )
{
$max = max( array( $max, $v[$val] ) );
}
return $max;
}
$highestBuy = getMax($thisArray, 'buy');
foreach($thisArray as $i=>element){
if($element['buy'] == $highestBuy){
$thisArray[$i]['highestBuy'] = 'yes';
} else {
$thisArray[$i]['highestBuy'] = 'no';
}
}
In this case, both apple and lemon will have highestBuy a yes value. But now I want to find out which item is the most popular by checking their sell if there are two or more same value of highestBuy. Which is the most simple or fastest way to make the output like:
array([0] => array([item]=>apple [buy]=>50 [sell]=>30 [mostPopular]=>no)
[1] => array([item]=>lemon [buy]=>50 [sell]=>60 [mostPopular]=>yes)
[2] => array([item]=>banana [buy]=>40 [sell]=>20 [mostPopular]=>no)
[3] => array([item]=>orange [buy]=>20 [sell]=>30 [mostPopular]=>no)
)
Thanks in advance.
EDIT:
What I want to do is:
find out the highest buy
If this value occur only once(which means there are one highest buy in the array) then push the [mostPouplar]=>yes into the array
If not(there are two or more same highest value), then find out the highest sell.
That's mean if the highest value is unique, it will stop doing further action. If not, it will keep going to find secondary highest value in an array. Is it possible to achieve this?
Sort array with your rules and take first element
$array = array( '0' => array('item'=>apple, 'buy'=>50 ,'sell'=>30),
'1' => array('item'=>lemon, 'buy'=>50, 'sell'=>60),
'2' => array('item'=>banana, 'buy'=>40, 'sell'=>20),
'3' => array('item'=>orange, 'buy'=>20 ,'sell'=>30)
);
usort($array,
function($a, $b) {
$res = $b['buy'] - $a['buy'];
if (!$res) $res = $b['sell'] - $a['sell'];
return $res; });
result:
Array (
[0] => Array ( [item] => lemon [buy] => 50 [sell] => 60 )
[1] => Array ( [item] => apple [buy] => 50 [sell] => 30 )
[2] => Array ( [item] => banana [buy] => 40 [sell] => 20 )
[3] => Array ( [item] => orange [buy] => 20 [sell] => 30 ) )
I had changed the getMax() to return the index of the most popular item
function getMax($array, $val, $val2)
{
$max_item = 0;
foreach( $array as $k => $v )
{
if($array[$max_item][$val] <= $v[$val] && $array[$max_item][$val2] <= $v[$val2])
$max_item = $k;
}
return $max_item;
}
$highestBuy = getMax($thisArray, 'buy', 'sell');
foreach($thisArray as $i => $element){
$thisArray[$i]['mostPopular'] = ($i == $highestBuy) ? 'yes' : 'no';
}
I can't seem to wrap my head around this.
I am given an array in PHP that looks something like this:
array (
0 => array (
0 => 50,
1 => 0.80
),
1 => array (
0 => 300,
1 => 0.50
),
2 => array (
0 => 600,
1 => 0.30
),
3 => array (
0 => 1000,
1 => 0.20
),
4 => array (
0 => 4000,
1 => 0.10
)
);
An array of arrays where the first index of the inner array represents a quantity while the second index represents a price.
I want to import this data into my database, but in a specific way.
I have specific quantities that I like to keep track of that are defined by the following array:
array(10,100,500,1000,5000,10000);
I then want to make the original array more fine tuned to quantities and prices that I would like to see. So in this particular example, I would like an array that looks like this:
array (
0 => array (
0 => 100,
1 => 0.80
),
1 => array (
0 => 500,
1 => 0.50
),
2 => array (
0 => 1000,
1 => 0.20
),
3 => array (
0 => 5000,
1 => 0.10
)
);
My new array will only contain the specific quantity indexes.
If a quantity exists in the original array, I use that price. If it doesn't exist, I would use the price of the next lowest quantity. If no lower quantity exists, I don't want to see that quantity in the new array.
I have been able to accomplish what I want for the most part with the following code:
function getRelativePrices($pricearray) {
$relativeprices = array();
$types = array(10,100,500,1000,5000,10000);
foreach ($types as $q) {
$new_array = array();
foreach ($pricearray as $index => $array) {
if ($q >= $array[0]) {
$new_array = array($q, $array[1]);
}
}
if (sizeof($new_array)) {
$relativeprices[] = $new_array;
}
}
return $relativeprices;
}
The only problem with the above is that I am getting extra data that I do not want. In the example I provided, I am getting a 5th index/array at the end that looks like:
4 => array (
0 => 10000,
1 => 0.10
)
I don't want this last piece, since I find it redundant considering that I know that 5000 pieces cost $0.10 each, so I can assume that 10000 will cost the same price when "4000" is the highest quantity given in the original array.
So I want to ask for help in removing this last piece.
Also, I was wondering if someone had a better coding method in general for converting this array.
You could just do in your inner foreach:
foreach ($pricearray as $index => $array) {
if ($q >= $array[0]) {
if($q == 10000) { continue; }
$new_array = array($q, $array[1]);
}
}
OK I think this should do the trick. I think the problem was in your comparison... See code:
function getRelativePrices($pricearray) {
$relativeprices= array();
$types = array(10,100,500,1000,5000,10000);
foreach($pricearray as $p) {
$new_array = array();
foreach($types as $t) {
if($p[0] <= $t) {
$new_array = array($t,$p[1]);
break;
}
}
if(sizeof($new_array)) {
$relativeprices[] = $new_array;
}
}
return $relativeprices;
}
Here is an example of my test based on your code examples:
function getRelativePrices($pricearray) {
$relativeprices= array();
$types = array(10,100,500,1000,5000,10000);
foreach($pricearray as $p) {
$new_array = array();
foreach($types as $t) {
if($p[0] <= $t) {
$new_array = array($t,$p[1]);
break;
}
}
if(sizeof($new_array)) {
$relativeprices[] = $new_array;
}
}
return $relativeprices;
}
$test = array (
0 => array (
0 => 50,
1 => 0.80
),
1 => array (
0 => 300,
1 => 0.50
),
2 => array (
0 => 600,
1 => 0.30
),
3 => array (
0 => 1000,
1 => 0.20
),
4 => array (
0 => 4000,
1 => 0.10
)
);
print_r(getRelativePrices($test));
And the output was:
Array
(
[0] => Array
(
[0] => 100
[1] => 0.8
)
[1] => Array
(
[0] => 500
[1] => 0.5
)
[2] => Array
(
[0] => 1000
[1] => 0.3
)
[3] => Array
(
[0] => 1000
[1] => 0.2
)
[4] => Array
(
[0] => 5000
[1] => 0.1
)
)