9

i need to sort an array in php based on value, array use some numbers for keys and values, for example like this:

$a = array(70 => 1 ,82 => 5  ,61 => 3 ,55 => 1 ,34 => 2 ,53 => 2 ,21 => 4 ,13 => 5);

i like to sort it like this:

Array
(
    [82] => 5
    [13] => 5
    [21] => 4
    [61] => 3
    [34] => 2
    [53] => 2
    [70] => 1
    [55] => 1
)

i used arsort and it worked, but there is a problem because this function make change defult sorted keys and sort array to:

Array
(
    [13] => 5
    [82] => 5
    [21] => 4
    [61] => 3
    [53] => 2
    [34] => 2
    [55] => 1
    [70] => 1
)
hakre
  • 193,403
  • 52
  • 435
  • 836
Vahid
  • 382
  • 1
  • 6
  • 19
  • 1
    @MadaraUchiha: I 'm not so sure. Unless I 'm mistaken the OP wants a stable sort, not a multiple-criteria sort. – Jon Oct 01 '12 at 15:46
  • i read all of them, none exactly related to this problem! – Vahid Oct 01 '12 at 15:47
  • This entire page is now obsolete. See https://wiki.php.net/rfc/stable_sorting#:~:text=A%20stable%20sort%20guarantees%20that,some%20part%20of%20that%20data. Stable sorting has been implemented 3 years ago. – mickmackusa Apr 24 '23 at 04:12

6 Answers6

14

Construct a new array whose elements are the original array's keys, values, and also position:

$temp = array();
$i = 0;
foreach ($array as $key => $value) {
  $temp[] = array($i, $key, $value);
  $i++;
}

Then sort using a user-defined order that takes the original position into account:

uasort($temp, function($a, $b) {
 return $a[2] == $b[2] ? ($a[0] - $b[0]) : ($a[2] < $b[2] ? 1 : -1);
});

Finally, convert it back to the original associative array:

$array = array();
foreach ($temp as $val) {
  $array[$val[1]] = $val[2];
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • funny in almost 5 years no-one noticed that instead of `($a[0] > $b[0])` it should be `($a[0] > $b[0] ? 1 : -1)`, otherwise `false` is returned on reversed elements, which causes an undefined order. (Note also that `$a[0] == $b[0]` is impossible.) – Walter Tross May 26 '17 at 12:50
  • 1
    @WalterTross Good catch. I changed it to `$a[0] - $b[0]`. I could also change the ternary at the end to `$b[2] - $a[2]`, but if it ain't broke ... – Barmar May 26 '17 at 15:58
4

This is because the sort family of functions are not stable. If you need the sort to be stable then you either have to implement it yourself, or iterate over the sorted result and "correct" the positions of the elements using array_splice.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • 1
    +1 from me, just wanted to add the link to [this answer](http://stackoverflow.com/a/4353844/1229023) describing the process of creating a sorting function in more details. ) – raina77ow Oct 01 '12 at 15:49
  • what about this way: arsort($a); asort($a); arsort($a); this worked! – Vahid Oct 01 '12 at 15:49
  • 3
    @Vahid: It *happened* to work. There is no guarantee that it will work next time. – Jon Oct 01 '12 at 15:56
4

Simple solution with array_multisort.

$assoc = [
    70 => 1,
    82 => 5,
    61 => 3,
    55 => 1,
    34 => 2,
    53 => 2,
    21 => 4,
    13 => 5,
];

$keys = array_keys($assoc);
array_multisort($assoc, SORT_DESC, range(1, count($assoc)), $keys);
$assoc = array_combine($keys, $assoc);

print_r($assoc);
mpyw
  • 5,526
  • 4
  • 30
  • 36
2

It is kinda a big workaround, but it does work:

$a = array(70 => 1 ,82 => 5  ,61 => 3 ,55 => 1 ,34 => 2 ,53 => 2 ,21 => 4 ,13 => 5);
$b = max($a);
$c = min($a);
$d = 0;
$sorted_list = array();
while($b >= $c){
    foreach($a as $key => $value){
        if($value == $b){
            $sorted_list[$key] = $value;
        }
    }
    $b--;
}

vardump output:

array(8) { [82]=> string(1) "5" [13]=> string(1) "5" [21]=> string(1) "4" [61]=> string(1) "3" [34]=> string(1) "2" [53]=> string(1) "2" [70]=> string(1) "1" [55]=> string(1) "1" } 
Maringo
  • 109
  • 4
  • good! but why i get Undefined offset for line $sorted_list[$key] .= $value;? – Vahid Oct 01 '12 at 16:14
  • I don't know why you get that and I didn't, but I do know how to fix it. Two lines added in my answer. – Maringo Oct 02 '12 at 06:55
  • error disappeared, but array have wrong and empty values: Array ( [70] => 1 [82] => [61] => [55] => 1 [34] => [53] => [21] => [13] => ) – Vahid Oct 02 '12 at 13:31
0

You can create your own sorting funtion that meets your custom sorting criteria and then use usort() to iterate all over the array using the function you created to sort the array.

slash28cu
  • 1,614
  • 11
  • 23
  • What sorting function could he use to get a stable sort? The original position in the array is not passed as a parameter to the comparison function. – Barmar Oct 01 '12 at 17:51
0

PHP use quicksort as base sorting-algorithms. You hae two options:

  1. first Uses usort and define a compare-function, which respect the former order
  2. programm your own stable sorting-mechanism

I have programmed a package porth/avalanchesort (https://github.com/porthd/avalanchesort) on github, which contains a recursive naturell-merge-sort. You can use your own comparsionfunction and your own data-structure. The package contains an example for associative arrays and for list-arrays.

padina
  • 77
  • 5