8

What I'm trying to do is sort a multi-dimensional array that contains decimal values. From what I've tested, floats are having trouble being ordered properly.

Array
(
    [0] => Array
        (
            [company] => Ebay
            [weight] => 4.6
        )

    [1] => Array
        (
            [company] => Ebay
            [weight] => 1.7
        )

    [2] => Array
        (
            [company] => Ebay
            [weight] => 3.7
        )
)


usort($array, 'order_by_weight');

// Sorts DESC highest first
function order_by_weight($a, $b) {
    return $b['weight'] - $a['weight'];
}

What is the best way to sort these numbers in descending?

mickmackusa
  • 33,121
  • 11
  • 58
  • 86
stwhite
  • 2,516
  • 4
  • 30
  • 58
  • "floats have trouble being ordered properly" --- no they aren't, you've confused something. – zerkms Apr 11 '13 at 05:11
  • @zerkms I might be misreading the docs, but I'm not misreading the incorrectly ordered values. http://php.net/manual/en/function.usort.php. Check this out, which is said in the php docs: "Caution Returning non-integer values from the comparison function, such as float, will result in an internal cast to integer of the callback's return value. So values such as 0.99 and 0.1 will both be cast to an integer value of 0, which will compare such values as equal." – stwhite Apr 11 '13 at 05:15
  • I've taken your code and it just works: http://ideone.com/cqW85m Have you even tried to run it? – zerkms Apr 11 '13 at 05:17
  • @Zerkms You're trolling this post, please be constructive here. "omg, replace it to.." is unacceptable. Please respond using an "answer". – stwhite Apr 11 '13 at 05:19
  • done, there is an answer (took your code and slightly changed it) – zerkms Apr 11 '13 at 05:20

5 Answers5

20
$arr = array(
    array('company' => 'A', 'weight' => 4.6),
    array('company' => 'B', 'weight' => 1.7),
    array('company' => 'C', 'weight' => 3.7),
);

usort($arr, 'order_by_weight');

function order_by_weight($a, $b) {
    return $b['weight'] > $a['weight'] ? 1 : -1;
}

var_dump($arr);

PS: it's not a rocket science - this exact "trick" is used as the first example at http://php.net/usort

zerkms
  • 230,357
  • 57
  • 408
  • 498
  • I like it, much shorter than array_multisort and simple to read/use! – Benz Apr 11 '13 at 05:26
  • @Benz: it could be even shorter if we used anonymous functions – zerkms Apr 11 '13 at 05:26
  • Totally true, but we don't know the TS PHP version, I'm not for sure, but I thought that the minimal PHP version for anonymous functions is PHP 5.4. – Benz Apr 11 '13 at 05:29
  • @Benz: it's 5.3, which is quite popular these days – zerkms Apr 11 '13 at 05:30
  • 1
    @Zerkms I get that it's not rocket science, but sometimes after looking at a problem for a while, you overlook simple problems. Thank you for taking the time to answer my question. – stwhite Apr 11 '13 at 05:35
3

You can do this with anonymous function in just one line

$arr = array(
    array('company' => 'A', 'weight' => 4.6),
    array('company' => 'B', 'weight' => 1.7),
    array('company' => 'C', 'weight' => 3.7),
);
usort($arr, function($a, $b) { return $b['weight'] > $a['weight'] ;});

print_r($arr);

Hope this helps :)

Sabari
  • 5,847
  • 1
  • 22
  • 34
1

You can sort the array using array_multisort, altough, this is often used to sort on multiple array values instead of one.

echo "<pre>";

 $a = array(
     array('company' => 'ebay', 'weight' => 4.6), 
     array('company' => 'ebay', 'weight' => 1.7),
     array('company' => 'ebay', 'weight' => 3.7),
     array('company' => 'ebay', 'weight' => 2.7),
     array('company' => 'ebay', 'weight' => 9.7),
     array('company' => 'ebay', 'weight' => 0.7),
 );

 $company = array();
 $weight = array();

 foreach($a as $key=>$val) {
     array_push($company, $val['company']);
     array_push($weight, $val['weight']);
 }

 array_multisort($weight, SORT_ASC, $a);

 print_r($a);
Benz
  • 2,207
  • 10
  • 19
0

As sorting algo here is good example for sort multi dimension array without using any more inbuilt php function

$multiarr = array('0'=>array(
        "hashtag" => "a7e87329b5eab8578f4f1098a152d6f4",
        "title" => "Flower",
        "order" => 3),

'1' => array(
        'hashtag' => "b24ce0cd392a5b0b8dedc66c25213594",
        "title" => "Free",
        "order" => 2),
'2' => array('hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b',
        'title' => 'Ready',
        'order' => 1
    ));

sorting function :

    function multisort (&$array, $key) {
$valsort=array();
$ret=array();
reset($array);
foreach ($array as $ii => $va) {
    $valsort[$ii]=$va[$key];
}
asort($valsort);
foreach ($valsort as $ii => $va) {
    $ret[$ii]=$array[$ii];
}
$array=$ret;

}

multisort($multiarr,"order")enter code here

: output :

Array
 (
[2] => Array
    (
        [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
        [title] => Ready
        [order] => 1
    )

[1] => Array
    (
        [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
        [title] => Free
        [order] => 2
    )

[0] => Array
    (
        [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
        [title] => Flower
        [order] => 3
    )

)

liyakat
  • 11,653
  • 2
  • 38
  • 45
0

In case someone wants a more concise code, especially to handle equals condition you will add if condition before @zerkms's solution

using ceil will round fractions up and will sort the decimal numbers correctly

usort($data, function($a, $b) 
      {
        return ceil($a[$_GET['sortby']] - $b[$_GET['sortby']]); 
      });