I have seen strange behavior that I don't quite get. I do the following:
$array = [
'a' => [
'a1' => [
'a11' => 1,
'a12' => 2
],
'a2' => [
'a21' => 3,
'a22' => 4
],
],
'b' => [
'b1' => [
'b11' => 1,
'b12' => 2
],
'b2' => [
'b21' => 3,
'b22' => 4
],
],
];
foreach ($array as $strLevel1 => &$arrLevel1)
{
foreach ($arrLevel1 as $strLevel2 => &$arrLevel2)
{
foreach ($arrLevel2 as $strLevel3 => &$varLevel3)
{
$varLevel3 = 0;
}
}
}
echo '<pre>';
var_dump($array);
echo '</pre>';
foreach ($array as $strLevel1 => $arrLevel1)
{
}
echo '<pre>';
var_dump($array);
echo '</pre>';
The result is as follows:
array(2) {
["a"]=>
array(2) {
["a1"]=>
array(2) {
["a11"]=>
int(0)
["a12"]=>
int(0)
}
["a2"]=>
array(2) {
["a21"]=>
int(0)
["a22"]=>
int(0)
}
}
["b"]=>
&array(2) {
["b1"]=>
array(2) {
["b11"]=>
int(0)
["b12"]=>
int(0)
}
["b2"]=>
&array(2) {
["b21"]=>
int(0)
["b22"]=>
&int(0)
}
}
}
array(2) {
["a"]=>
array(2) {
["a1"]=>
array(2) {
["a11"]=>
int(0)
["a12"]=>
int(0)
}
["a2"]=>
array(2) {
["a21"]=>
int(0)
["a22"]=>
int(0)
}
}
["b"]=>
&array(2) {
["a1"]=>
array(2) {
["a11"]=>
int(0)
["a12"]=>
int(0)
}
["a2"]=>
array(2) {
["a21"]=>
int(0)
["a22"]=>
int(0)
}
}
}
As you can see, in the first output everything is ok. But in the second one, the b-named branch of the array is replaced by the a-named branch. This is because of the referencing I did. If I put a "&" before $arrLevel1 in the last loop, it works again.
Why is that? Am I doing something wrong with the references? Or should I don't use them at all and do array manipulation only fully qualified without any reference?
Thanks in advance.
Maybe you should unset the reference to $arrLevel1 after your loop, till you reused the var for the second loop.
foreach ($array as $strLevel1 => &$arrLevel1)
{
foreach ($arrLevel1 as $strLevel2 => &$arrLevel2)
{
foreach ($arrLevel2 as $strLevel3 => &$varLevel3)
{
$varLevel3 = 0;
}
}
}
// remove reference
unset($arrLevel1);
echo '<pre>';
var_dump($array);
echo '</pre>';
foreach ($array as $strLevel1 => $arrLevel1)
{
}
echo '<pre>';
var_dump($array);
echo '</pre>';
A way to come around unset is to use unique names for your loop variables or - if you want to loop over the same array again - just also use an reference loop var.
foreach ($array as $strLevel1 => &$arrLevel1)
{
foreach ($arrLevel1 as $strLevel2 => &$arrLevel2)
{
foreach ($arrLevel2 as $strLevel3 => &$varLevel3)
{
$varLevel3 = 0;
}
}
}
// also use a reference
foreach ($array as $strLevel1 => &$arrLevel1)
{
}
Most of the time, it might be simplier to just don't use references or move the loop in an "atomic" function which just does the manipulation and returns the result.
Related
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'];
});
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 have an array like this:
array(5) {
[0]=> array(1) { ["go-out"]=> string(7) "#0d4b77" }
[1]=> array(1) { ["cycling"]=> string(7) "#1472b7" }
[2]=> array(1) { ["diving"]=> string(7) "#1e73be" }
[3]=> array(1) { ["exploring"]=> string(7) "#062338" }
[4]=> array(1) { ["eating"]=> string(7) "#f79e1b" }
}
Let's say I have the first value like 'cycling', so how can I find the '#147217' value?
I have been trying a lot of combinations of
foreach ( $array as $key => list($key1 ,$val)) {
if ($key1 === $id) {
return $val;
}
}
But no luck.
Ideas?
You can use array_column -
array_column($your_array, 'cycling');
DEMO
You should also add the checks for key's existence.
you may still make one loop
$id = "cycling";
foreach($array as $val)
if(isset($val[$id])) echo $val[$id];
Demo on Evail.in
I have reformated tour code, try this, that works:
$array = array(
0 => array("go-out" => "#0d4b77"),
1 => array("cycling" => "#1472b7"),
2 => array("diving" => "#1e73be"),
3 => array("exploring" => "#062338"),
4 => array("eating" => "#f79e1b")
);
$id = "cycling";
foreach ($array as $key => $entry) {
if ($entry[$id]) {
echo $entry[$id];
}
}
$array = array(
0 => array("go-out" => "#0d4b77"),
1 => array("cycling" => "#1472b7"),
2 => array("diving" => "#1e73be"),
3 => array("exploring" => "#062338"),
4 => array("eating" => "#f79e1b")
);
$search = "cycling";
foreach ($array as $key => $entry)
if (isset($entry[$search]))
echo $entry[$search];
That works.
Nice day.
I'm trying to sort a multidimensional array (in fact that it is multidimensional doesn't matter since I'm always only sorting one dimension).
function orderSort($a, $b) {
if ($a['order'] == $b['order']) return 0;
return($a['order'] < $b['order']) ? -1 : 1;
}
$nav = array(
"section" => array(
"header" => array(),
"main" => array()
),
"link" => array(
"header" => array(),
"main" => array()
)
);
$DATA = array(
array(
"type" => "section",
"subtype" => "main",
"data" => array("name" => "/Basic", "order" => 1, "parent" => "bbb")
),
array(
"type" => "link",
"subtype" => "main",
"data" => array("name" => "Home", "link" => array("/"), "order" => 1, "parent" => "/Basic")
)
);
foreach($DATA as $ele) {
if(!array_key_exists($ele['data']['parent'], $nav[$ele['type']][$ele['subtype']]))
$nav[$ele['type']][$ele['subtype']][$ele['data']['parent']] = array($ele['data']);
else
array_push($nav[$ele['type']][$ele['subtype']][$ele['data']['parent']], $ele['data']);
}
var_dump($nav['section']['main']);
echo '<br><br>';
foreach($nav['section']['main'] as $ele) {
uasort($ele, 'orderSort');
$nav['section']['main'] = $ele;
}
var_dump($nav['section']['main']);
The first var_dump returns:
array(1) {
["bbb"]=> array(1) {
[0]=> array(3) {
["name"]=> string(6) "/Basic"
["order"]=> int(1) ["parent"]=> string(3) "bbb"
}
}
}
As you can see there is a key named bbb (Sorry for that... highly conceptional). Now the second output:
array(1) {
[0]=> array(3) {
["name"]=> string(6) "/Basic"
["order"]=> int(1)
["parent"]=> string(3) "bbb"
}
}
Suddenly bbb is gone. In fact the whole array (with only a single element) has disappeared.
My question is, can I somehow prevent this from happening? I never asked for this kind of of optimization. Of course sorting this with only one element doesn't make any sense but still.
foreach($nav['section']['main'] as $ele) {
uasort($ele, 'orderSort');
$nav['section']['main'] = $ele;
}
Okay. And which is the key? you just forgot the keys (you are overwriting the parent of the original array with a new array instead of the original array itself):
foreach($nav['section']['main'] as $key => $ele) {
uasort($ele, 'orderSort');
$nav['section']['main'][$key] = $ele;
}
would be correct, but by reference is even better:
foreach($nav['section']['main'] as &$ele) {
uasort($ele, 'orderSort');
}
Your problem is here:
foreach($nav['section']['main'] as $ele) {
uasort($ele, 'orderSort');
$nav['section']['main'] = $ele;
}
This needs to be
foreach($nav['section']['main'] as $index => $ele) {
uasort($ele, 'orderSort');
$nav['section']['main'][$index] = $ele;
}
You were replacing the whole $nav['section']['main'] with the first element.