uasort is removing keys/arrays - php

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.

Related

Get lowest key - array value in multidimensional array PHP

So, I got array that looks something like this:
[65]=>
array(2) {
[0]=>
array(2) {
["p"]=>
float(234)
["sp"]=>
float(234)
}
[1]=>
array(2) {
["p"]=>
float(53)
["sp"]=>
float(5)
}
[2]...
[3]...
}
The idea is to go through each of 0 - N values of key 65 array, and only keep one with smallest "p", others should be removed / filtered out.
This should be done in PHP.
Anyone has any idea?
I tried something like this:
$array = array_filter($array, function ($value, $key) use ($a) {
return $a['p'] <= $value['p'];
}, ARRAY_FILTER_USE_BOTH);
where $value is 1 of elements inside 65 keyed-array and $a is current pair that is being added dynamically. So when ever its added, I go through existing elements and if its lowest, it should stay, and others get instant filtered out, but if its higher, it should automatically be filtered out.
Thank you!
You can use array_reduce() to get the lowest "p"-value:
$arr = [
65 => [
["p" => 234, "sp" => 234],
["p" => 53, "sp" => 5],
["p" => 530, "sp" => 5],
]
];
function getLowestKey($carry, $item) {
if ($item['p'] < $carry || !$carry) {
$carry = $item['p'];
}
return $carry;
}
$lowestKey = array_reduce($arr[65], 'getLowestKey');
var_dump($lowestKey); // int(53)
Edit:
I just noticed there is a second part to your question, sorry about that. Once you found out the "lowest p" you can then just filter the array with that knowledge:
$lowestPs = array_filter($arr[65], function($item) use ($lowestKey) {
return $item['p'] == $lowestKey;
});
var_dump($lowestPs);
/*
array(2) {
[1]=>
array(2) {
["p"]=>
int(53)
["sp"]=>
int(5)
}
[2]=>
array(2) {
["p"]=>
int(53)
["sp"]=>
int(5)
}
}
*/
This solution works even if multiple entries have the same lowest "p" value (like 53 in the above example), all of those will stay.
Use array_column() to do an array_multisort() on the 'p' value for the records inside key 65.
<?php
$col = 'p'; // set the column you want to order on
$column = array_column($arr[65], $col);
array_multisort($column, SORT_ASC, $arr[65]);
$arr[65] = $arr[65][0]; // only keep the record with lowest 'p' value
demo
If have more than 1 nested levels, you might also use a recursive approach checking the value of p, keeping the array with the lowest value.
$arrays = [
65 => [
["p" => 234, "sp" => 234],
[
["p" => 53,"sp" => 5],
[
["p" => 54,"sp" => 1],
["p" => 53,"sp" => 7],
]
], [
"p" => 255,
"sp" => 235
],
]
];
function loop($array, &$coll = [], &$min = null)
{
foreach ($array as $key => $value) {
if (is_array($value)) {
loop($value, $coll, $min);
} elseif ($key === "p") {
if ($min === null) $min = $value;
if ($min > $value) {
$coll = [$array];
$min = $value;
continue;
}
if($value === $min) $coll[] = $array;
}
}
return $coll;
}
$arrays[65] = loop($arrays[65]);
var_dump($arrays);
Output
array(1) {
[65]=>
array(2) {
[0]=>
array(2) {
["p"]=>
int(53)
["sp"]=>
int(5)
}
[1]=>
array(2) {
["p"]=>
int(53)
["sp"]=>
int(7)
}
}
}
See another php demo.

Referenced array iteration in php results in strange result

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.

Sort array by the value of the key

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

array search multidimensional in php?

I want to create a function that for a random array will search for a given key and will return all values for that key in an array. Here is what I have written so far...
$testArray = array (
'subArray1' => array(
'key1' => "Sub array 1 value 1",
'key2' => "Sub array 1 value 2",
'key3' => array(
'subkey1' => array(
'subsubkey' => 'sub sub sub value',
),
),
),
'subArray2' => array(
'key1' => "Sub array 2 value 1",
'key2' => "Sub array 2 value 2",
'key3' => array(
'subkey1' => array(
'subsubkey' => 'sub sub sub value 2',
),
),
),
);
function recursiveSearch($testArray,$key,$results)
{
// var_dump($testArray);
if(is_array($testArray)){
foreach($testArray as $k => $v){
if($k == $key){
return $v;
}
else if(is_array($v)){
array_push($results, recursiveSearch($v,$key,$results));
}
}
}
else{
return ;
}
return $results;
}
$empt = array();
$output = recursiveSearch($testArray,'subsubkey',$empt);
var_dump($output);
This the output I get at the moment... I want to get a simple array with the values in it.
array(2) {
[0]=>
array(1) {
[0]=>
array(1) {
[0]=>
string(17) "sub sub sub value"
}
}
[1]=>
array(2) {
[0]=>
array(1) {
[0]=>
array(1) {
[0]=>
string(17) "sub sub sub value"
}
}
[1]=>
array(2) {
[0]=>
array(1) {
[0]=>
array(1) {
[0]=>
string(17) "sub sub sub value"
}
}
[1]=>
string(19) "sub sub sub value 2"
}
}
}
I am not really sure why the result array is like this ...
The format for the result array that I want is :
['sub sub sub value','sub sub sub value 2']
An improved version of xPheRe
/**
* Recursive find in the given $array and $needle.
* #param $array The input array.
* #param $needle The needle to find.
* #return Returns all the values find by the given key.
*/
function recursiveFind(array $array, $needle)
{
$iterator = new RecursiveArrayIterator($array);
$recursive = new RecursiveIteratorIterator($iterator,
RecursiveIteratorIterator::SELF_FIRST);
$results = array();
foreach ($recursive as $key => $value) {
if ($key === $needle) {
array_push($results, $value);
}
}
return $results;
}
Usage
$output = recursiveFind($testArray, 'subsubkey');
var_dump($output);
Output
array(2) {
[0]=>
string(17) "sub sub sub value"
[1]=>
string(19) "sub sub sub value 2"
}
The updated function of my version is as follows:
function recursiveSearch($testArray,$key){
$empt = array();
function recurSearch($testArray,$key,$results)
{
if(is_array($testArray)){
foreach($testArray as $k => $v){
if($k === $key){
array_push($results,$v);
}
else if(is_array($v)){
$temp = array();
$tempres = recurSearch($v,$key,$temp);
$results = array_merge($results,$tempres);
}
}
}
return $results;
}
$res = recurSearch($testArray,$key,$empt);
return $res;
}
seems to work : )

Search values in php array

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.

Categories