2

I have following array

Array
(
[0] => Array
    (
        [label] => Germany
        [conversions] => 1
    )

[1] => Array
    (
        [label] => United States
        [conversions] => 8
    )

[2] => Array
    (
        [label] => France
        [conversions] => 1
    )

[3] => Array
    (
        [label] => China
        [conversions] => 1
    )

[4] => Array
    (
        [label] => Philippines
        [conversions] => 1
    )

[5] => Array
    (
        [label] => Turkey
        [conversions] => 1
    )

)

I want to order following array, first by conversions (desc), then by label (asc)

output will have following sequence:

United States
China
France
Germany
Philippines
Turkey
kapa
  • 77,694
  • 21
  • 158
  • 175
I-M-JM
  • 15,732
  • 26
  • 77
  • 103

6 Answers6

4

If using >= PHP 5.3...

usort($arr, function($a, $b) {

   $diff = $b['conversions'] - $a['conversions'];

   if ( ! $diff) {
      return strcmp($a['label'], $b['label']);
   } 

   return $diff; 

});

It is relatively simple to make it work with < PHP 5.3.

hakre
  • 193,403
  • 52
  • 435
  • 836
alex
  • 479,566
  • 201
  • 878
  • 984
  • Typo in the second `conversions` index. – Core Xii Jul 18 '11 at 11:55
  • 1
    note that functions can only be defined this way in PHP 5.3 and above. If you're using an older version of PHP, you'll need to define your function in the traditional way, and the second param of `usort()` would be the function name. (you may want to do this anyway, if you plan to use the same sorting function in more than one place) – Spudley Jul 18 '11 at 11:56
  • @alex: Edited: The code did not work at all even in PHP 5.3 (it's not complete so gives syntax errors) and well, the sort order was wrong. – hakre Jul 18 '11 at 12:17
  • @hakre: Thanks, I didn't test it. I would have if the OP gave the array in an easy copy + paste format. :) – alex Jul 18 '11 at 12:18
  • 1
    @alex: little hint: visit my profile page and look into the grey box on the right. there is one link. I know perfectly how you feel ;) – hakre Jul 18 '11 at 12:20
  • @hakre: That is brilliant! Kudos to you and +1 for your answer. – alex Jul 18 '11 at 12:21
1

You need to use PHP's usort() function. This allows you to write a function which determines the sort order, so you can sort things into any order you like.

The function will be called repeatedly by the usort() algorithm, and will give you two parameters, being the two elements of the array that it wants to sort at any given moment. Your function should return -1 if the first of those two elements is bigger, +1 if it the second is bigger, and zero if they are to be considered the same for the purposes of the sort.

See the PHP manual page for more info and examples: http://php.net/manual/en/function.usort.php

Spudley
  • 166,037
  • 39
  • 233
  • 307
1

I preferred array_multisort PHP Manual in my answer below as you can specify the sort order with parameters.

Next to flexibility it should be faster than using usort which has the problem that it's not really parametrized for the sort order, so not re-inventing the wheel as well.

For more comfort, wrap it up into a function to specify the keys as strings (Demo):

$sorted = $multisortByKey($array, 'conversions', SORT_DESC, 'label', SORT_ASC);

as in:

$array = array(
  0 => array(
    'label' => 'Germany',
    'conversions' => 1,
  ),
  1 => array(
    'label' => 'United States',
    'conversions' => 8,
  ),
  2 => array(
    'label' => 'France',
    'conversions' => 1,
  ),
  3 => array(
    'label' => 'China',
    'conversions' => 1,
  ),
  4 => array(
    'label' => 'Philippines',
    'conversions' => 1,
  ),
  5 => array(
    'label' => 'Turkey',
    'conversions' => 1,
  ),
);

$multisortByKey = function(array $a) {
    $args = func_get_args();
    $a = array_shift($args);
    $extract = function($k) use($a) {return array_map(function($v) use($k) { return $v[$k]; }, $a); };
    # NOTE: The following check/for-loop is not entirely correct 
    # as multiple sort parameters per entry are allowed. I leave this
    # for practice.
    $c = count($args);
    if(!$c%2) throw new InvalidArgumentException('Parameter count mismatch');
    for($i=0;$i<$c;$i+=2)
        $args[$i] = $extract($args[$i]);
    $args[] = &$a;
    call_user_func_array('array_multisort', $args);
    return $a;
};

$sorted = $multisortByKey($array, 'conversions', SORT_DESC, 'label', SORT_ASC);

var_dump($sorted);
hakre
  • 193,403
  • 52
  • 435
  • 836
0

Try the following: (didn't test it, source: PHP Example #3)

foreach ($data as $key => $row) {
    $label[$key]   = $row['label'];
    $conversion[$key] = $row['conversion'];
}

array_multisort($conversion, SORT_DESC, $label, SORT_ASC, $data);
hakre
  • 193,403
  • 52
  • 435
  • 836
Sascha Galley
  • 15,711
  • 5
  • 37
  • 51
0

You can use usort to provide your own sorting function

usort($a, function($x, $y) {
  return $y["conversions"] < $x["conversions"] ? 1 :
    ($x["conversions"] < $y["conversions"] ? -1 :
      strcmp($x["label"], $y["label"]))
    );
});
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
0

try this

$myArray="your array";

<?php

foreach($myArray as $c=>$key) {
    $sort_conv[$c] = $key['conversions'];
    $sort_lable[$c] = $key['label'];
   }

array_multisort($sort_conv, SORT_ASC, $sort_lable, SORT_STRING, $myArray);
print_r($myArray);
?>
jeni
  • 442
  • 1
  • 4
  • 12
  • Actually this isn't correct. Indeed your proposed code sorts at first by conversions in ascending order, but as a second sorting criteria OP didn't ask for an alphabetical sorting, but rather using a specific sorting country criterion... – Faye D. Jun 27 '21 at 18:11