7

I have an array as following and I want to order that array by the value of the key "attack". First keys of the arrays (15, 13, 18) are ID of some certain item from database, so I don't want these keys to be changed when the array is sorted. Any help would be greatly appreciated.

This is the array:

$data = array(
    '15' => array(
        'attack' => '45', 'defence' => '15', 'total' => '10'
    ),
    '13' => array(
        'attack' => '25', 'defence' => '15', 'total' => '10'
    ),
    '18' => array(
        'attack' => '35', 'defence' => '15', 'total' => '10'
    )
);
PhearOfRayne
  • 4,990
  • 3
  • 31
  • 44
Chris Ford
  • 99
  • 1
  • 1
  • 7

3 Answers3

18

Use uasort():

This function sorts an array such that array indices maintain their correlation with the array elements they are associated with, using a user-defined comparison function.

This is used mainly when sorting associative arrays where the actual element order is significant.

Example:

function cmp($a, $b) {
    if ($a['attack'] == $b['attack']) {
        return 0;
    }
    return ($a['attack'] < $b['attack']) ? -1 : 1;
} 

uasort($data, 'cmp');

If the values are always strings, you can also use strcmp() in the cmp() function:

function cmp($a, $b) {
    return strcmp($a['attack'], $b['attack']);
} 

Update:

To sort in descending order you just have to change the return values:

return ($a['attack'] < $b['attack']) ? 1 : -1;
//                                     ^----^

or to pick up @salathe's proposal:

return $b['attack'] - $a['attack'];
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Boo for overly complicated callback. `$a['attack'] - $b['attack'];` would suffice. – salathe Jul 19 '10 at 14:23
  • @salathe: True, this would be more efficient. But this is more compliant with the examples of the documentation. – Felix Kling Jul 19 '10 at 14:26
  • @Chris: `uasort` sorts the array in place. It returns `true` on success (mentioned in the documentation I linked to). If you want to print the result, you have to print the array. – Felix Kling Jul 19 '10 at 14:28
  • Of course, I print the array using print_r but it only prints 1 to the screen. – Chris Ford Jul 19 '10 at 14:31
  • @Chris: Not for me. I get the sorted array... must be something else in your code. – Felix Kling Jul 19 '10 at 14:32
  • Sorry, my bad. I saw I was printing something else. I have one more question. How do I sort the value by descending order? – Chris Ford Jul 19 '10 at 14:34
  • @Felix -- I guess the docs could offer more varied examples and/or state that the values don't have to be in the set -1, 0 and 1. – salathe Jul 19 '10 at 16:08
3

Simply use array_multisort

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

// Sort the data with attack descending
array_multisort($attack, SORT_DESC, $data);

Update:

array_multisort works when the array keys are string but in the case of numeric array keys, the array_multisort destroys the first level keys of the array.

First level array keys are preserved

<?php
$data = array(
    'a' => array(
        'attack' => '45', 'defence' => '15', 'total' => '10'
    ),
    'b' => array(
        'attack' => '25', 'defence' => '15', 'total' => '10'
    ),
    'c' => array(
        'attack' => '35', 'defence' => '15', 'total' => '10'
    )
);
print_r($data);

foreach ($data as $key => $row) {
    $key = (string)$key;
    $attack[$key]  = $row['attack'];
}
print_r($attack);

// Sort the data with attack descending
array_multisort($attack, SORT_DESC, $data);
print_r($data);
?>

OUTPUT:

Array
(
    [a] => Array
        (
            [attack] => 45
            [defence] => 15
            [total] => 10
        )

    [b] => Array
        (
            [attack] => 25
            [defence] => 15
            [total] => 10
        )

    [c] => Array
        (
            [attack] => 35
            [defence] => 15
            [total] => 10
        )

)
Array
(
    [a] => 45
    [b] => 25
    [c] => 35
)
Array
(
    [a] => Array
        (
            [attack] => 45
            [defence] => 15
            [total] => 10
        )

    [c] => Array
        (
            [attack] => 35
            [defence] => 15
            [total] => 10
        )

    [b] => Array
        (
            [attack] => 25
            [defence] => 15
            [total] => 10
        )

)

First level array keys are NOT preserved

<?php
$data = array(
    '15' => array(
        'attack' => '45', 'defence' => '15', 'total' => '10'
    ),
    '13' => array(
        'attack' => '25', 'defence' => '15', 'total' => '10'
    ),
    '18' => array(
        'attack' => '35', 'defence' => '15', 'total' => '10'
    )
);
print_r($data);

foreach ($data as $key => $row) {
    $key = (string)$key;
    $attack[$key]  = $row['attack'];
}
print_r($attack);

// Sort the data with attack descending
array_multisort($attack, SORT_DESC, $data);
print_r($data);
?>

OUTPUT:

Array
(
    [15] => Array
        (
            [attack] => 45
            [defence] => 15
            [total] => 10
        )

    [13] => Array
        (
            [attack] => 25
            [defence] => 15
            [total] => 10
        )

    [18] => Array
        (
            [attack] => 35
            [defence] => 15
            [total] => 10
        )

)
Array
(
    [15] => 45
    [13] => 25
    [18] => 35
)
Array
(
    [0] => Array
        (
            [attack] => 45
            [defence] => 15
            [total] => 10
        )

    [1] => Array
        (
            [attack] => 35
            [defence] => 15
            [total] => 10
        )

    [2] => Array
        (
            [attack] => 25
            [defence] => 15
            [total] => 10
        )

)

https://www.php.net/manual/en/language.types.array.php

The key can either be an int or a string. The value can be of any type.

Additionally, the following key casts will occur:

Strings containing valid decimal ints, unless the number is preceded by a + sign, will be cast to the int type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.

Floats are also cast to ints, which means that the fractional part will be truncated. E.g. the key 8.7 will actually be stored under 8.

Bools are cast to ints, too, i.e. the key true will actually be stored under 1 and the key false under 0.

Null will be cast to the empty string, i.e. the key null will actually be stored under "".

Arrays and objects can not be used as keys. Doing so will result in a warning: Illegal offset type.

Mukesh Chapagain
  • 25,063
  • 15
  • 119
  • 120
  • This answer is inappropriate/incorrect because it destroys the ids/keys in the first level. Proof: https://phpize.online/s/tt – mickmackusa Aug 30 '23 at 22:20
-1
$result = [];
foreach ($data as $key => $value) {
    $result[$key] = $value;
    asort($result[$key]);
}
print_r($result);
Adriaan
  • 17,741
  • 7
  • 42
  • 75
Unknown
  • 7
  • 1
  • 1
    Please read [answer] and [edit] your answer to contain an explanation as to why this code would actually solve the problem at hand. Always remember that you're not only solving the problem, but are also educating the OP and any future readers of this post. – Adriaan Aug 30 '23 at 14:07
  • 1
    This answer is not helpful and does not provide the desired behavior of sorting by attack. Proof: https://phpize.online/s/pt – mickmackusa Aug 30 '23 at 22:23