PHP: uasort not working [duplicate] - php

This question already has answers here:
How to Sort a Multi-dimensional Array by Value
(16 answers)
Closed 11 months ago.
I have the following array
$infoArray = Array
(
[Shockwafe Ultra 9.2] => Array
(
[0] => 8
[1] => 45 Hz - 18.000 Hz
[2] => 9.2
[3] => 1
[4] => 1
[5] => 1
[6] =>
[7] =>
[8] => B+
[9] => B+
[10] => A
[11] => B
)
[Bose 5.1 SoundTouch 300] => Array
(
[0] => 9
[1] => 45 Hz - 20.000 Hz
[2] => 5.1
[3] => 1
[4] => 1
[5] => 1
[6] => 1
[7] => 1
[8] => A
[9] => A
[10] => A+
[11] => A+
)
[Sonos 5.1 System] => Array
(
[0] => 10
[1] => 31.5 Hz - 20.000 Hz
[2] => 5.1
[3] => 1
[4] => 1
[5] => 1
[6] => 1
[7] => 1
[8] => A+
[9] => A+
[10] => A+
[11] => A+
)
)
I am trying to sort it with the use of PHP. I want to sort by the [0] value in each array member. So the order should be, Sonos first, Bose second, Shockwafe third.
My PHP code looks as following:
function sortByOrder($a, $b) {
return $a[0] - $b[0]; }
uasort($infoArray, 'sortByOrder');
I've tried this on wamp, where it succesfully arranges the order like i'd want. However, online in my Wordpress installation, this does NOT work. It simply does not re-arrange the array. It should be noted, that I am working inside functions.php within a shortcode. I tried moving the sortByOrder() function outside of the shortcode area, with no success.
Any ideas what goes wrong?

function sortByOrder($a, $b) {
$result = 0;
if ($b['rating'] > $a['rating']) {
$result = 1;
} elseif ($b['rating'] < $a['rating']) {
$result = -1;
}
return $result;
}
This ended up being my solution. It has something to do with decimal numbers, I'm not exactly sure why it worked. Solution in OP is fine if you work with whole numbers, but this is required for decimal numbers.

Ran into the same issue. Turns out the comparison callback is expected to return an integer value. If you return a float, your value will be casted to an int. This means that values between -1 and 1 all become 0. That's why whole numbers work: the difference between them is always at least 1 if they aren't the same.
PHP 7.4 introduced arrow functions and the "spaceship operator". Those make comparator functions very concise. Ordering "by rating" would therefore be:
uasort($infoArray, fn($a, $b) => $a['rating'] <=> $b['rating']);

Related

PHP Working with an array to find ranges and missing numbers

I have an array that looks like this:
[0] => Array
(
[1] => 5
[2] => 4
[3] => 3
[5] => 1
[7] => 1
[8] => 2
[9] => 3
[10] => 4
[11] => 5
)
[1] => Array
(
[1] => 6
[2] => 5
[4] => 3
[5] => 2
[6] => 1
[8] => 3
[9] => 4
[10] => 5
[11] => 6
)
[2] => Array
(
[1] => 7
[2] => 6
[3] => 5
[4] => 4
[5] => 3
[6] => 2
[7] => 3
[8] => 4
[11] => 7
)
I have an order of operations I'm trying to go through and I really don't know where to go from here. Any suggestions would be of great help.
First I give my class the number of items I want to return. For example here we'll use 4.
I want to loop through and find the item in the array that has the lowest value.
I want to look at the keys to the items around (it included) and be sure they're not missing a number if they are..reject it..
In this example the first one you would come to would be:
[5] => 1
Now looking around it you see that the keys are missing some numbers. So no combination of 4 will get that to match any 4 in the proper order.
[1] => 5
[2] => 4
[3] => 3
[5] => 1 //this one
[7] => 1
[8] => 2
[9] => 3
In this situation I want it to move onto the next case.
[7] => 1
Notice this one will work due to the keys being 7,8,9,10.
[7] => 1
[8] => 2
[9] => 3
[10] => 4
This is what I would like returned first..but I don't even know how to begin to get there.
Further more there are situations like this..Say for example there are no 1's at all in the dataset..and only this lone 2 in the last one.
[0] => Array
(
[1] => 5
[2] => 4
[3] => 3
[5] => 3
[7] => 3
[8] => 3
[9] => 3
[10] => 4
[11] => 5
)
[1] => Array
(
[1] => 6
[2] => 5
[4] => 3
[5] => 3
[6] => 3
[8] => 3
[9] => 4
[10] => 5
[11] => 6
)
[2] => Array
(
[1] => 7
[2] => 6
[5] => 3
[6] => 2 // this one
[7] => 3
[8] => 4
[11] => 7
)
The following wont work:
[6] => 2 // this one
[7] => 3
[8] => 4
[11] => 7
but this one will:
[5] => 3
[6] => 2 // this one
[7] => 3
[8] => 4
I have no idea on how to approach this.. If someone could offer some advice it would be GREATLY appreciated. Thanks so much in advance.
The following assumes your data is in an array called $data. I'll describe it in steps, then pull it all together as a function.
Step 1 find the min value:
$minValue=min($data);
Step 2 loop through the array looking for all values that are that value:
foreach($data as $index => $value){
if($value == $minValue){
// $index is a candidate!
}
}
Step 3 Check if $valuesToReturn entries exist after index:
$success=true;
for($i=1;$i<=$valuesToReturn;$i++){
if(!array_key_exists($index + $i,$data)){
// Candidate failed.
$success=false;
break;
}
}
Step 4 If the candidate was successful, return it.
if($success){
return $index;
}
Putting that all together, we get this:
function findSuitableIndex($data,$valuesToReturn){
// Min:
$minValue=min($data);
foreach($data as $index => $value){
if($value == $minValue){
// $index is a candidate!
// test if index is actually suitable:
$success=true;
for($i=1;$i<=$valuesToReturn;$i++){
if(!array_key_exists($index + $i,$data)){
// Candidate failed.
$success=false;
break;
}
}
if($success){
return $index;
}
}
}
// If we fell down here, we failed to find any successful results.
return -1;
}
Working sample:
Code on eval.in
Here are some suggestions. Your exact implementation would depend on your particular situation.
To loop through each element in the array, you could use a foreach loop.
foreach ($arr[0] as $index => $value) {
// Here, $arr[0][$index] == $value;
}
To check if a key exists or not, you could use array_key_exists.
if ( !array_key_exists($index - 1, $arr[0]) ) {
// The previous index is missing in the array.
}
A simple (but inefficient) way to find a contiguous sequence of k indices with the smallest value at the first index would be to find the smallest element and check if the contiguous sequence exists; if not, find the next smallest element and recursively check until you have completed processing the largest element.
You could also try finding all contiguous sequences of at least length k and then selecting the sequence with the smallest value at the first index.
Hope this helps!

Re-order PHP array by middle key as start (Circular Sorting)

very basic question however I have had some trouble finding the answers on PHP.NET.
I have the following array:
Array (
[1] => Array
(
[1] => 4
[2] => 1
[3] => 5
[4] => 3
)
[2] => Array
(
[5] => 2
[6] => 8
[7] => 7
[8] => 6
)
[3] => Array
(
[9] => 10
[10] => 9
[11] => 12
[12] => 11
)
[4] => Array
(
[13] => 15
[14] => 16
[15] => 14
[16] => 13
)
)
I want the array to be re-ordered so that the key number 3 in the first series of the array becomes the first, then the rest to be re-ordered from there to eventually get the result of:
Array (
[3] => Array
(
[9] => 10
[10] => 9
[11] => 12
[12] => 11
)
[4] => Array
(
[13] => 15
[14] => 16
[15] => 14
[16] => 13
)
[1] => Array
(
[1] => 4
[2] => 1
[3] => 5
[4] => 3
)
[2] => Array
(
[5] => 2
[6] => 8
[7] => 7
[8] => 6
)
)
I am looking for a way to do this so I can define the array, then the first level key I need to sort by, and then it will return the array in this way.
The standard PHP keys didn't seem to offer something like this, so it would be good to be able to have a separate function such as $newArray = reorder_array($array, $key);
I don't require any sorting of the second level, only the initial 4 main / first level array sections.
You help is greatly appreciated as I have been sitting on this one for awhile without a clear and simple solution.
You re-ordering can be simply implemented with one foreach loop, like:
function reorderArray($array, $key)
{
$found = false;
foreach($array as $k=>$v)
{
$found = $found || $k===$key;
if(!$found)
{
unset($array[$k]);
$array[$k] = $v;
}
//else break can be added for performance issues
}
return $array;
}
with usage
$array=[1=>'foo', 4=>'bar', 9=>'baz', 'test'=>51];
var_dump(reorderArray($array, 9));
var_dump(reorderArray($array, 'test'));
var_dump(reorderArray($array, 'no_such_key'));//original array in result
-check this demo. If keys are consecutive numerics, however, this can be easily implemented with array_slice() calls.

PHP - count frequency of array values

Is there a way in php to count how often a value exists in a large array?
So if I have an array like this:
$array = "1,2,3,4,joe,1,2,3,joe,joe,4,5,1,6,7,8,9,joe";
is there a way to output a new array that tells me (and sorts) which is used most and how many for each?
$result = array(
[joe] => 4
[1] => 3
[2] =>2
etc...
)
I've seen the php array_count_values, but can this be sorted by most -> least? or is there an easier way?
Thanks everyone!
Sort them after counting them with arsort()
$result = array_count_values(explode(',', $array));
arsort($result);
Array
(
[joe] => 4
[1] => 3
[2] => 2
[4] => 2
[3] => 2
[9] => 1
[8] => 1
[5] => 1
[6] => 1
[7] => 1
)

Sorting Multidimensional Array by Specific Key

EDIT: For anyone who might come across this post with a similar problem, It was solved by taking konforce's supplied answer and tweaking around a bit with the custom sorting function:
function cmp($a, $b) {
if ($a[5] == $b[5]) {
return ($a[3] < $b[3]) ? -1 :1;
}
return ($a[5] > $b[5]) ? -1 : 1;
}
Notice $a[5] == $b[5] does not return zero. It was changed to check who has the most losses and then sort it in ASC order. I'm sure you can even keep going and add another if-statement in there in-case they have the same losses.
Lastly, all you do is usort($ARRAY, "cmp"); and finito!!!
Original Post
My apologies for coming up with yet another MD Array sorting question but I'm just not getting it. I've searched aplenty
for a solution and although many sites have provided what seemed like a logical answer I still have not been able to figure it out.
My problem is since I'm still learning its been rather difficult for me to grasp the concept of using usort with a custom comparing
function. Atleast, thats what I have seen the most when others have tried to sort MD Arrays.
I'm working on a small project to sharpen up on my php skills. Its a very basic tournament standings script that holds a team's information within an array. I would like to sort the array by most points($array[X][X][5]).
So the array looks something like this:
Array (
[0] => Array (
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
)
[1] => Array (
[0] => Array (
[0] => strenx
[1] => 9
[2] => 5
[3] => 1
[4] => 3
[5] => 18
)
)
[2] => Array (
[0] => Array (
[0] => rapha
[1] => 10
[2] => 8
[3] => 1
[4] => 1
[5] => 25
)
) [3] => Array (
[0] => Array (
[0] => ronald reagan
[1] => 5
[2] => 4
[3] => 0
[4] => 1
[5] => 13
)
)
)
I would like to sort it by most points(cell #5), so it would look like this after sorting:
Array (
[0] => Array (
[0] => Array (
[0] => rapha
[1] => 10
[2] => 8
[3] => 1
[4] => 1
[5] => 25
)
)
[1] => Array (
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
)
[2] => Array (
[0] => Array (
[0] => strenx
[1] => 9
[2] => 5
[3] => 1
[4] => 3
[5] => 18
)
)
[3] => Array (
[0] => Array (
[0] => ronald reagan
[1] => 5
[2] => 4
[3] => 0
[4] => 1
[5] => 13
)
)
)
The player with 25 points would be at the top, followed by 18, 18, and lastly 13. Sorry for my earlier post, was having difficulty wording my question correctly. Thanks in advanced!
I think you want something like this:
usort($standings, function($a, $b) { return $b[0][5] - $a[0][5]; });
Or prior to PHP 5.3:
function cmp($a, $b) { return $b[0][5] - $a[0][5]; }
usort($standings, 'cmp');
When using usort, the $a and $b parameters will be one "layer" into the supplied array. So in your case, an example of $a or $b will be:
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
I'm not sure why you have an extra containing array there, but as you can see, you want to sort based on the [0][5] position.
usort($standings[0][0][5], 'cmp') won't work because the first parameter isn't an array to sort, it's just a single number, the points.

How to get "maximum range" from an array

Index is 00 to 23 (24-hour time)
What I am trying to accomplish is to get largest maximum range.
Each array will have a maximum of 24 elements. Of these, I want to get all the ones which are high (a range).
So,
for first array - 10,16,19,19
second - 18,19,20
third - 9,11.
Array
(
[00] => 10
[01] => 19
[02] => 10
[03] => 4
[04] => 1
[13] => 16
[14] => 2
[15] => 5
[16] => 2
[17] => 3
[18] => 1
[19] => 1
[20] => 1
[21] => 5
[22] => 1
[23] => 2
)
Array
(
[09] => 6
[10] => 20
[11] => 18
[12] => 19
[13] => 3
[15] => 11
[16] => 9
[18] => 10
)
Array
(
[00] => 4
[01] => 3
[12] => 4
[16] => 4
[21] => 9
[22] => 11
[23] => 6
)
The problem is, these values could get changed entirely, like this one -
Array
(
[13] => 117
[14] => 221
[15] => 211
[16] => 145
[17] => 23
[18] => 15
[19] => 1
)
Any solution for this?
Thank you,people.
It's a bit unclear how you want to choose which values are 'high', but:
In PHP 5.3+
$filetered = array_filter($yourArray, function($v) {return $v > 10;});
Will return array with values higher than 10.
In PHP <5.3 you will need to createa callback function instead of passing a closure to array_filter.
Use array_keys() and than max() to get the maximum key value:
$keys = array_keys($myArray);
$maxKey = max($keys);
I think what you want (although it's not very clear what is a "high" value) can be accomplished with asort(). If you sort your array numerically:
asort($yourarray, SORT_NUMERIC);
Then you can just retrieve the first elements from the sorted array. You don't even specify how many elements should be retrieved, but I'm guessing it's 3, although you don't seem to want anything below 10, so just use array_slice() to extract the last three elements and if any of them is lower than 10 discard it.
Putting it all together would give something like:
asort($yourarray, SORT_NUMERIC);
$top3 = array_slice($yourarray, -3, null, true)
$filtered = array_filter($top3, function($v) {return $v > 10;});
Note: I used Mchl example on the final part of my answer.
You can use array_filter() to filter out those values that are not within the range:
function is_between_10_and_20($v)
{
return ($v >= 10 && $v <= 20);
}
$result = array_filter($arr, "is_between_10_and_20")

Categories