Sort Associative PHP Array By Number Then By String - php

I have an associative array in PHP that is created from a SQL Query. I've been sorting by just one column, but now I need to change the code to sort by two columns.
The two columns consist of a FLOAT and a STRING:
$array["FinalValue"] = float and
$array["Category"] = string
I'm using this right now to just sort by the one column (FinalMulti) which is a FLOAT:
usort($categorylist, function($a, $b){
if((float) $b['FinalMulti'] == (float) $a['FinalMulti']) return 0;
return ((float) $b['FinalMulti'] < (float) $a['FinalMulti']) ? - 1 : 1;
});
I've searched the site on how to do this and found an example that sorted by STRING then INTEGERS, but nothing quite in my order and nothing that builds on the code I'm currently using.
The other examples used strcmp and I've inserted it in few place and it doesn't work. For example, I tried:
usort($categorylist, function($a, $b){
if((float) $b['FinalMulti'] == (float) $a['FinalMulti']) {
return strcmp($b['CategoryName'], $a['CategoryName']);
}
return ((float) $b['FinalMulti'] < (float) $a['FinalMulti']) ? - 1 : 1;
});
I know strcmp compares strings so I feel like that there should be an if statement, but I don't know what I would return. While I'm decent at programing, my understanding of usort is not strong.
In the end, ["FinalMulti"] needs to be sorted DESC from highest to lowest while ["CategoryName"] needs to be sorted in alphabetical order (A to Z). The first letter in all ["CategoryName"] strings are capitalized.
Thanks in advance!

usort($categorylist, function($a, $b) {
if ((float)$b['FinalMulti'] == (float)$a['FinalMulti']) {
return strcmp($a['Category'], $b['Category']);
}
return ((float)$b['FinalMulti'] < (float)$a['FinalMulti']) ? -1 : 1;
});

You can use array_multisort with array_column:
array_multisort(
array_column($categorylist, 'FinalMulti'), SORT_DESC,
array_column($categorylist, 'CategoryName'), SORT_ASC,
$categorylist
);
3v4l.org demo

Related

How can I sort an array by two criteria?

I have an array I want to echo alphabetized while ignoring the number that starts each string, as such:
0 Apple
1 Apple
3 Apple
0 Banana
1 Banana
0 Carrot
//...
When I sort, the number is sorted first. So, I've tried asort, sort_string with no success.
$file = file("grades.txt");
asort($file, SORT_STRING);
Can I look only at the alphabet characters and ignore numbers? Or can I ignore the first character and sort starting with the second character? What should I do to get the above result?
It would be great if the numbers could be in order AFTER the arrays are echoed alphabetically, but it is not demanded if too difficult to do.
Maybe try php's uasort function.
http://php.net/manual/en/function.uasort.php
function cmp($a, $b) {
if ($a[2] == $b[2]) {
return 0;
}
return ($a[2] < $b[2]) ? -1 : 1;
}
uasort($array, 'cmp');
You can swap the position of the alphabetic part and numeric part, and use strcmp() to compare the string in usort().
http://php.net/manual/en/function.usort.php
usort($arr, function($a, $b) {
$a = $a[2].' '.$a[0];
$b = $b[2].' '.$b[0];
return strcmp($a, $b);
});
You can use preg_replace() to remove numbers from beginning of strings, preg_replace() accepts third param ( subject ) as an array ( the search and replace is performed on every item ).
$file = preg_replace( '/^[\d\s]+/', '', file("grades.txt") );
arsort( $file );
EDIT:
Use preg_replace( '/^([\d\s]+)(.+)/', '$2 $1', file("grades.txt") ) to shift the numbers to the end of string.
For this you need a custom order function, which you can do with uasort(), e.g.
Simply explode() your string by a space and save the number and the string in a variable. Then if string is the same order the elements by the number. Else sort by the string.
uasort($arr, function($a, $b){
list($numberA, $stringA) = explode(" ", $a);
list($numberB, $stringB) = explode(" ", $b);
if(strnatcmp($stringA, $stringB) == 0)
return $numberA < $numberB ? -1 : 1;
return strnatcmp($stringA, $stringB);
});

Sort php sub array based on sub key

Here is a snippet of my array that is used in php 5.3.x :
$arr[$category][$item][$attr_qty] = 3;
$arr[$category][$item][$attr_price] = 12.00;
$category are arbitrary integers, as are $item, as are $attr_qty and $attr_price.
Is there a quick way of sorting, by $attr_qty, the items in each category?
Using integers makes the code easier, but I get the feeling I will have to use associative arrays.
You can use usort which allows you to specify a custom sorting function
usort($arr, 'customSortFunction');
function customSortFunction($a, $b)
{
if ($a['item']['attr_qty'] > $b['item']['attr_qty']) return 1; //First element is bigger
elseif ($a['item']['attr_qty'] < $b['item']['attr_qty']) return -1; //Second element is bigger
else return 0; //Both are equal
}

Best way to sort 2d Array Php

I'm reading from a text file that has 2 columns. name,rank So it looks like this:
quxerm,6
brock,5
chris,15
So the 2d array looks like [0][0] = quxerm and [0][1]=6 [1][0] = brock [1][1]=5
I already have them into a 2d array like I showed above.
I need to sort these values in descending order by the integer column. How can I sort this?
#CBergau's answer is almost perfect but the order will be ascending instead of descending.
To get it descending just switch the return values of the compare function which is called by usort. See http://www.php.net/manual/en/function.usort.php for more information.
function cmp(array $a, array $b) {
return ($a[1] < $b[1]) ? 1 : -1;
}
usort($arr, 'cmp');
Example: http://codepad.org/QRTQLxTh
You could also extend the compare function for example to order ascending by name when the rank is the same by using strcmp. See http://www.php.net//manual/en/function.strcmp.php for more information.
function cmp(array $a, array $b) {
if ($a[1] == $b[1]) {
return strcmp($a[0], $b[0]);
}
return ($a[1] < $b[1]) ? 1 : -1;
}
Example: http://codepad.org/SeRTE3Ym
Note: I've not enough reputation yet to just comment on #CBergau's answer.
Use map instead, and then you can use all the functions relatives to maps like this.
take the array as arr[i][j].
try comparing only by changing the values of i.
for(int i=0;i<3;i++)
for(int k=1;k<3;k++)
if(arr[i][1]>arr[k][1])
max=i
and you can retrieve max by :-
arr[max][0]//name of max
arr[max][1]//value of max
$sorted = array();
foreach($yourArray as $a){
$sorted[$a[1]] = $a[0];
}
ksort($sorted);
vardump($sorted);
This should sort by the integer column:
usort(
$data,
function ($arrayOne, $arrayTwo) {
return ($arrayOne[1] < $arrayTwo[1]) ? -1 : 1;
}
);
If there are no duplicate names, you can simply assign the rank for the key (name), and sort that array while preserving keys.
$data["quxerm"] = 6;
$data["brock"] = 5;
$data["chris"] = 15;
asort($data, SORT_NUMERIC);

Sorting a multidimensional array by numeric value of a dimension that's not the first

I am creating a search capability for a forum program I'm building. At one point I have an array called searchResults which is numeric and contains 'score' as one of its dimensions (others are 'timeStarted', 'authorUID', and 'TID')
So, this array is in disarray at this point and I need to organize it to where $searchResults[1] will be the highest 'score' and [2] will have the second highest, etc. I looked at array_multisort on php.net but got rapidly lost in how it worked. So how would I sort $searchResults in numeric order (rearrange the keys) descending with a descending order of a further dimension 'sort' as the sorting mechanism? There really isn't any code to go with it but if you need a layout of how the array looks, here you go:
$searchResults:
[1] - ['timeStarted']
['authorUID']
['score'] <- Need to sort first dimension by this value descending
['TID']
etc.
Thanks for any help.
usort allows sorting by any specified comparison function
$cmp = function($a,$b) {return $b['score'] - $a['score'];};
usort($searchResults, $cmp);
In this case, $cmp is a function that compares two elements $a and $b of $searchResults based on value of ['score']. $cmp returns 0 for equality, negative val if $a['score'] is greater, positive val if $b['score'] is greater. It would normally be the other way around, but a descending sorting order is desired.
The function you want is usort. Look at example #2:
<?php
function cmp($a, $b)
{
return strcmp($a["fruit"], $b["fruit"]);
}
$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";
usort($fruits, "cmp");
while (list($key, $value) = each($fruits)) {
echo "\$fruits[$key]: " . $value["fruit"] . "\n";
}
?>
The output:
$fruits[0]: apples
$fruits[1]: grapes
$fruits[2]: lemons

PHP Sorting a multi-dimensional array by field name

I have tried adapting this code to use to sort a multidimensional array on a named key/field. The field is an integer what I need to sort smallest to biggest.
function myCmp($a, $b)
{
return strcmp($a["days"], $b["days"]);
}
uasort($myArray, "myCmp");
This sorts the arrays as I need but in the wrong order. At the moment it sorts biggest to smallest, not using natural order. I need to sort smallest to biggest in natural order (eg 2 comes before 5, 12 and 24).
strnatcmp() is your friend
e.g. (using a php 5.3 closure/anonymous function):
<?php
$myArray = array( 'foo'=>array('days'=>2), 'bar'=>array('days'=>22), 'ham'=>array('days'=>5), 'egg'=>array('days'=>12) );
uasort($myArray, function($a, $b) { return strnatcmp($a["days"], $b["days"]); });
foreach($myArray as $k=>$v) {
echo $k, '=>', $v['days'], "\n";
}
prints
foo=>2
ham=>5
egg=>12
bar=>22
You can just reverse the parameters of strcmp :
function myCmp($a, $b)
{
return strcmp($b["days"], $a["days"]);
}
uasort($myArray, "myCmp");
Since you want to sort in natural order you should not be using strcmp, you can do:
function myCmp($a, $b)
{
if ($a['days'] == $b['days']) return 0;
return ($b['days'] > $a['days']) ? -1 : 1;
}
Here is a working example.

Categories