For example, I have this array:
$bills = array(
array("bill_id"=>"1", "product_id"=>"1", "total"=>"10"),
array("bill_id"=>"2", "product_id"=>"2", "total"=>"20"),
array("bill_id"=>"3", "product_id"=>"1", "total"=>"30"),
array("bill_id"=>"4", "product_id"=>"1", "total"=>"40"),
array("bill_id"=>"5", "product_id"=>"2", "total"=>"50")
);
We need to add the totals of each produdct into a single array, i.e. What is the best clean fast way to generate the following array from the above one:
$products = array(
array("product_id"=>"1", "total"=>"80"),
array("product_id"=>"2", "total"=>"70")
);
the fastest way to sum this is index array, something like this
$products = array();
foreach ($bills as $bill) {
$key = $bill['product_id'];
if (isset($products[$key])) {
$products[$key]['total'] += $bill['total'];
} else {
$products[$key] = $bill;
}
}
var_dump($products);
output
array(2) {
[1]=>
array(3) {
["bill_id"]=>
string(1) "1"
["product_id"]=>
string(1) "1"
["total"]=>
int(80)
}
[2]=>
array(3) {
["bill_id"]=>
string(1) "2"
["product_id"]=>
string(1) "2"
["total"]=>
int(70)
}
}
to browse the invoice list
foreach($products as $key=>$bill) {
var_dump($bill);
}
Thie simplest approach is a single-pass loop.
$byProduct = [];
foreach($bills as $bill)
{
$key = $bill['product_id'];
if (!isset($byProduct[$key])) {
$byProduct[$key] = [
'product_id' => $key,
'total' => 0
];
}
$byProduct[$key]['total'] += $bill['total'];
}
Result of var_dump($byProduct):
array(2) {
[1] =>
array(2) {
'product_id' =>
string(1) "1"
'total' =>
int(80)
}
[2] =>
array(2) {
'product_id' =>
string(1) "2"
'total' =>
int(70)
}
}
Another approach is to use array_walk but it is pretty much the same in terms of complexity:
$byProduct = [];
array_walk($bills, function(&$bill) use (&$byProduct) {
$key = $bill['product_id'];
if (!isset($byProduct[$key])) {
$byProduct[$key] = [
'product_id' => $key,
'total' => 0
];
}
$byProduct[$key]['total'] += $bill['total'];
});
Related
I have an array like this
array(2) {
["sys_ID"]=> string(32) "ab0ce921dba8a810f6db3892399619d9" ["sites"]=> array(5) {
[0]=> array(2) {
["sys_ID"]=> string(32) "448ce5a1dba8a810f6db3892399619ba" ["service"]=> string(4) "IDMB" } [1]=> array(2) {
["sys_ID"]=> string(32) "448ce5a1dba8a810f6db3892399619ba" ["service"]=> string(4) "ODMB" } [2]=> array(2) {
["sys_ID"]=> string(32) "598ce5a1dba8a810f6db3892399619bc" ["service"]=> string(4) "IDMB" } [3]=> array(2) {
["sys_ID"]=> string(32) "876ce5a1dba8a810f6db38923996199f" ["service"]=> string(4) "IDMB" } [4]=> array(2) {
["sys_ID"]=> string(32) "876ce5a1dba8a810f6db38923996199f" ["service"]=> string(4) "ODMB" } } }
If there is a duplicate ['sys_ID'] I want to change the first ['service'] => "IDMB,ODMB" then delete the duplicate value so there is only 1. So the above would become
array(2) {
["sys_ID"]=> string(32) "ab0ce921dba8a810f6db3892399619d9" ["sites"]=> array(5) {
[0]=> array(2) {
["sys_ID"]=> string(32) "448ce5a1dba8a810f6db3892399619ba" ["service"]=> string(4) "IDMB,ODMB" } [1]=> array(2) {
["sys_ID"]=> string(32) "598ce5a1dba8a810f6db3892399619bc" ["service"]=> string(4) "IDMB" } [2]=> array(2) {
["sys_ID"]=> string(32) "876ce5a1dba8a810f6db38923996199f" ["service"]=> string(4) "IDMB,ODMB" } ]} }
The first array was made getting POST values;
<?php
foreach ($_POST['services'] as $item) {
$parts = explode(',', $item);
$siteID = $parts[1];
$services = $parts[0];
$data['sites'][] = [
'sys_ID' => $siteID,
'service' => $services
];
}
?>
Change the way you generate your array to something like this:
<?php
$data = [
'sites' => [],
];
foreach ($_POST['services'] as $item) {
// Gather your data
$parts = explode(',', $item);
$siteID = $parts[1];
$services = $parts[0];
// Set flag to remember whether you need to add it
$add = true;
// Loop through existing data and check if the sys_ID already exists
foreach ($data['sites'] as &$dataDetails) {
// It does ... so just append your service
if ($dataDetails['sys_ID'] === $siteID) {
$add = false;
$dataDetails['service'] .= ',' . $services;
break;
}
}
// Couldn't find the sys_ID => Add new entry
if ($add) {
$data['sites'][] = [
'sys_ID' => $siteID,
'service' => $services
];
}
}
?>
It will be better to fill the array properly from the beginning; however I will still post a solution. We have the array defined like this:
$arr = array(
'sys_ID' => 'ab0ce921dba8a810f6db3892399619d9',
'sites' => array(
0 => array(
'sys_ID' => "448ce5a1dba8a810f6db3892399619ba",
'service'=> "IDMB"
),
1 => array(
'sys_ID' => "448ce5a1dba8a810f6db3892399619ba",
'service'=> "ODMB"
),
2 => array(
'sys_ID'=> "598ce5a1dba8a810f6db3892399619bc",
'service'=> "IDMB"
),
3 => array(
'sys_ID'=> "876ce5a1dba8a810f6db38923996199f",
'service'=> "IDMB"
),
4 => array(
'sys_ID'=> "876ce5a1dba8a810f6db38923996199f",
'service'=> "ODMB"
)
)
);
To merge the elements like described, you can do the following loop:
// For each site (1)...
for($i=0; $i<count($arr["sites"])-1; $i++){
// Take each of sites starting from the next one to the end (2)
for($j=$i+1; $j<count($arr["sites"]); $j++){
// If there is a match in sys_ID beteen (1) and (2)
if($arr["sites"][$i]['sys_ID'] == $arr["sites"][$j]['sys_ID']){
// Merge the service into (1) with comma separation
$arr["sites"][$i]['service'] = $arr["sites"][$i]['service'].",".$arr["sites"][$j]['service'];
// then delete (2)
array_splice($arr["sites"],$j,1);
$j--;
}
}
}
Note that this will reindex the numebers (1,2,3...). If you wish to preserve them, you can use unset() instead.
I've send an Array with data through FormData with Ajax.
I json encoded it first before sending it through and decoded it back at the PHP side.
My problem is this: "Trying to get property 'ID' of non-object" Or "Illegal string offset ID"
which is weird, since my array is like:
array(7) {
[0]=>
object(stdClass)#779 (2) {
["ID"]=>
string(1) "1"
["Value"]=>
string(19) "Onbeperkt helpdesk."
}
[1]=>
object(stdClass)#780 (2) {
["ID"]=>
string(1) "2"
["Value"]=>
string(43) "Een direct aanspreekpunt voor al uw vragen."
}
[2]=>
object(stdClass)#781 (2) {
["ID"]=>
string(1) "3"
["Value"]=>
string(20) "Een stabiel netwerk."
}
[3]=>
object(stdClass)#782 (2) {
["ID"]=>
string(1) "4"
["Value"]=>
string(43) "Uw belangrijke gegevens optimaal beveiligd."
}
}
The way I tried traversing the array:
$voordelen = json_decode($_POST['voordelen']);
echo var_dump($voordelen);
for ($i = 0; $i < count($voordelen); $i++) {
foreach ($voordelen[$i] as $key => $item) {
$voorArray = array(
"id" => $item->ID,
"item" => $item->Value,
"content_id" => $content->id // variable from code not shown here.
);
}
}
I also tried:
for ($i = 0; $i < count($voordelen); $i++) {
foreach ($voordelen[$i] as $item) {
$voorArray = array(
"id" => $item->ID,
"item" => $item->Value,
"content_id" => $content->id // Variable from code not shown here.
);
}
}
I also tried using $var['value'] instead of $var->value
But now I'm at a loss. Any help would be appreciated.
I think you are making an extra loop, did you try:
foreach ($voordelen as $item) {
$voorArray = array(
"id" => $item->ID,
"item" => $item->Value,
"content_id" => $content->id // Variable from code not shown here.
);
var_dump($voorArray);
}
What's wrong with just looping through it, since $voordelen is already an array:
$voordelen = json_decode($_POST['voordelen']);
foreach( $voordelen as $item )
{
$voorArray = array(
"id" => $item->ID,
"item" => $item->Value,
"content_id" => $content->id
);
// Do something with $voorArray here.
}
I've got this array, and I want to loop through it and add up the values prices that are on the same OrderDate. The other values like the Discount code I want to add as a sub-array.
array(3) {
[0]=>
array(4) {
["OrderDate"]=>
string(10) "2018-01-01"
["DiscountCode"]=>
NULL
["TotalRevenue"]=>
string(9) "147618.76"
["Discount_Revenue"]=>
string(8) "13453.77"
}
[1]=>
array(4) {
["OrderDate"]=>
string(10) "2018-01-01"
["DiscountCode"]=>
string(6) "SALE38"
["TotalRevenue"]=>
string(8) "364.92"
["Discount_Revenue"]=>
string(8) "4083.64"
}
[2]=>
array(4) {
["OrderDate"]=>
string(10) "2018-01-01"
["DiscountCode"]=>
string(9) "WELCOME20"
["TotalRevenue"]=>
string(6) "113.83"
["Discount_Revenue"]=>
string(6) "113.83"
}
}
So it should then look like:
array(3) {
[0]=>
array(4) {
["OrderDate"]=>
string(10) "2018-01-01"
["DiscountCodes"]=> array {
[0] => "DISCOUNT"
[1] => "SALE38"
[2] => "WELCOME20"
)
["TotalRevenue"]=>
string(9) "147618.76"
["Discount_Revenue"]=>
string(8) "13453.77"
}
}
I believe I have fixed it using this loop adding to the array if the key exists. Not sure if this is the most efficient way to do it though?
foreach ($results as $k => $result){
if( array_key_exists($result['OrderDate'], $arr)){
$arr[$result['OrderDate']]['price'] += $result['TotalRevenue'];
$arr[$result['OrderDate']]['new'] = false;
} else {
$arr[$result['OrderDate']] = array(
'price' => $result['TotalRevenue'],
'new' => true
);
}
}
I've come to my own solution if anyone else needs it.
$arr = array();
foreach ($results as $k => $result){
if( array_key_exists($result['OrderDate'], $arr)){
$arr[$result['OrderDate']]['Total_Revenue'] += $result['TotalRevenue'];
$arr[$result['OrderDate']]['Discount_Revenue'] += $result['Discount_Revenue'];
isset($result['DiscountCode']) ? $arr[$result['OrderDate']]['Discount_Code'][] = $result['DiscountCode'] : '';
$arr[$result['OrderDate']]['new'] = false;
} else {
$arr[$result['OrderDate']] = array(
'Total_Revenue' => $result['TotalRevenue'],
'Discount_Revenue' => $result['Discount_Revenue'],
'new' => true
);
isset($result['DiscountCode']) ? $arr[$result['OrderDate']]['Discount_Code'][] = $result['DiscountCode'] : '';
}
}
i'm trying to sort an array by the value of a sub-key in DESC order but I'm stuck.
I've could make it with ksort but it was in ascending order..
Here's my array :
array_by_lang => array(
[no] => array(
[3-1] => array(//some informations),
[3-10] => array(//informations),
[3-7] => array(//informations),
[5-1] => array(//informations)
)
)
what i want to obtain is something like :
array_by_lang => array(
[no] => array(
[5-1] => array(//informations),
[3-10] => array(//some informations),
[3-7] => array(//informations),
[3-1] => array(//informations)
)
)
Is that possible ? Thanks a lot
I think, you need "reversing natural sort by key". Just with array_multisort and array_reverse (see also natsort):
$array_by_lang = array(
'no' => array(
'3-1' => array('info_1'),
'3-10' => array('info_2'),
'3-7' => array('info_3'),
'5-1' => array('info_4'),
)
);
array_multisort(array_keys($array_by_lang['no']),SORT_NATURAL, $array_by_lang['no']);
$array_by_lang['no'] = array_reverse($array_by_lang['no']); // reverse natural order - "DESC"
var_dump($array_by_lang);
Output
array(1) {
["no"]=>
array(4) {
["5-1"]=>
array(1) {
[0]=>
string(6) "info_4"
}
["3-10"]=>
array(1) {
[0]=>
string(6) "info_2"
}
["3-7"]=>
array(1) {
[0]=>
string(6) "info_3"
}
["3-1"]=>
array(1) {
[0]=>
string(6) "info_1"
}
}
}
This might help -
$a = array(
'3-1' => array('//some informations'),
'3-10' => array('//informations'),
'3-7' => array('//informations'),
'5-1' => array('//informations')
);
## Array for keys
$temp= array();
foreach(array_keys($a) as $v) {
$t = explode('-', $v);
$temp[$t[0]][] = $t[1];
}
## Sort the keys
foreach($temp as &$ar) {
rsort($ar);
}
krsort($temp);
## Final array
$final= array();
foreach($temp as $k => $f) {
foreach($f as $v) {
$key = $k . '-' . $v;
$final[$key] = $a[$key];
}
}
var_dump($final);
Output
array(4) {
["5-1"]=>
array(1) {
[0]=>
string(14) "//informations"
}
["3-10"]=>
array(1) {
[0]=>
string(14) "//informations"
}
["3-7"]=>
array(1) {
[0]=>
string(14) "//informations"
}
["3-1"]=>
array(1) {
[0]=>
string(19) "//some informations"
}
}
DEMO
I want to make my flat array to a nested array but I can't seem to do this ;/
the code that I tryed to make it nested with:
<?php
$link = mysqli_connect("localhost", "db_phpnav", "jeXS9ftZhmJdzRWd", "db_phpNav");
$sql = "SELECT ID, PID, Naam FROM tb_nav";
$result = mysqli_query($link, $sql);
function convertToTree(array $flat, $idField = 'ID',
$parentIdField = 'PID',
$childNodesField = 'childNodes') {
$indexed = array();
foreach ($flat as $row) {
$indexed[$row[$idField]] = $row;
$indexed[$row[$idField]][$childNodesField] = array();
}
$root = null;
foreach ($indexed as $id => $row) {
$indexed[$row[$parentIdField]][$childNodesField][$id] =& $indexed[$id];
if (!$row[$parentIdField]) {
$root = $id;
}
}
return array($root => $indexed[$root]);
}
$rows = array();
while($row = mysqli_fetch_assoc($result)) {
$rows[] = $row;
}
convertToTree($rows);
?>
the array it gives out. it clearly doesn't do what I intended for.
array(3) {
[0]=>
array(3) {
["ID"]=>
string(1) "2"
["PID"]=>
NULL
["Naam"]=>
string(7) "Contact"
}
[1]=>
array(3) {
["ID"]=>
string(1) "5"
["PID"]=>
string(1) "2"
["Naam"]=>
string(7) "testing"
}
[2]=>
array(3) {
["ID"]=>
string(1) "6"
["PID"]=>
NULL
["Naam"]=>
string(8) "testing2"
}
}
How do i get the array to be nested nicely?
it should look more like this:
[0]=>
array(3) {
["ID"]=>
string(1) "2"
["PID"]=>
NULL
["Naam"]=>
string(7) "Contact"
'childNodes' => array(
2 => array(
["ID"]=>
string(1) "5"
["PID"]=>
string(1) "2"
["Naam"]=>
string(7) "testing"
'childNodes' => array ();
);
}
Suppose this is (kind of) what you want:
<?PHP
$entries = array();
$entries[] = array("ID" => "2", "PID" => NULL, "Naam" => "Contact");
$entries[] = array("ID" => "5", "PID" => "2", "Naam" => "testing");
$entries[] = array("ID" => "6", "PID" => NULL, "Naam" => "testing2");
function convertToTree($flat, $idField = 'ID', $parentIdField = 'PID', $childNodesField = 'childNodes', $curIdx = NULL)
{
$indexed = array();
foreach($flat as $row)
{
if ($row[$parentIdField] == $curIdx)
{
$indexed[$row[$idField]] = $row;
$indexed[$row[$idField]]["childNodes"] = convertToTree($flat, $idField, $parentIdField, $childNodesField, $row[$idField]);
}
}
return $indexed;
}
print_r($entries);
$tree = convertToTree($entries);
print_r($tree);
?>
/**
* Transform array to a nested structure.
* This gets a little complicated. Basically, we're creating a placeholder in
* $children to hold the child terms of each parent term. Then we create a
* reference to that element in the parent term. So nesting happens via magic.
*/
function arrayFlatToNested($array, $idKey = 'ID', $parentIdKey = 'PID', $childrenKey = 'childNodes'): array
{
$arrayNested = [];
$children = [];
foreach ($array as $element) {
// Create a placeholder for the object's children.
if (!isset($children[$element[$idKey]])) {
$children[$element[$idKey]] = [];
}
// Create a link to those children.
$element[$childrenKey] = &$children[$element[$idKey]];
if (!strlen($element[$parentIdKey])) {
$arrayNested[] = $element;
} else {
// Create a placeholder for the parent.
if (!isset($children[$element[$parentIdKey]])) {
$children[$element[$parentIdKey]] = [];
}
// Add this object to the parent, even if it doesn't exist yet.
$children[$element[$parentIdKey]][] = $element;
}
}
return $arrayNested;
}