1

I am working on gaming project, which needs sort and shuffle multidimensional array. First i need to sort based on bid. If multiple bids are same i need to sort based on priority. If bid & priority both are same means I need to shuffle those elements. For example we have 3 array elements in bid=0.4 & priority=4. Id's are 102,103 & 104. These array element position should be shuffled.

array(
    array('id' => 101, 'bid' => 0.5, 'priority' => 5),
    array('id' => 102, 'bid' => 0.4, 'priority' => 4),
    array('id' => 103, 'bid' => 0.4, 'priority' => 4),
    array('id' => 104, 'bid' => 0.4, 'priority' => 4),
    array('id' => 105, 'bid' => 0.3, 'priority' => 5),
    array('id' => 106, 'bid' => 0.3, 'priority' => 5),
    array('id' => 107, 'bid' => 0.2, 'priority' => 5),
    array('id' => 108, 'bid' => 0.7, 'priority' => 5),
    array('id' => 108, 'bid' => 0.1, 'priority' => 4)
);
Salman A
  • 262,204
  • 82
  • 430
  • 521
Palanikumar
  • 1,706
  • 5
  • 28
  • 51

7 Answers7

4

You should take a look at array_multisort to do that. There are examples on that page on how to sort a multi-dimensional array

<?php
// Obtain a list of columns
foreach ($data as $key => $row) {
  $bid[$key]  = $row['bid'];
  $prio[$key] = $row['priority'];
}

array_multisort($bid, SORT_ASC, $prio, SORT_ASC, $data);
?>

To shuffle I would add an extra column to the multidimensional array called "rand" and then fill it with a random number before you use multisort. Then you can add a 3th sort order on that column for shuffling.

Hugo Delsing
  • 13,803
  • 5
  • 45
  • 72
  • 1
    A simple usort is sufficient, for sorting at least. But I like your idea of adding a random number. – Salman A May 07 '13 at 08:12
  • 1
    Creating a function for sorting and using it isnt realy simpler then the above. A downvote because there is another option feels a little harsh. – Hugo Delsing May 07 '13 at 08:17
  • I did not downvote. But I am going to borrow your idea if you don't mind. – Salman A May 07 '13 at 08:18
2

Based on idea @Hugo's answer about using random weight:

$array = array(
    array('id' => 101, 'bid' => 0.5, 'priority' => 5),
    array('id' => 102, 'bid' => 0.4, 'priority' => 4),
    array('id' => 103, 'bid' => 0.4, 'priority' => 4),
    array('id' => 104, 'bid' => 0.4, 'priority' => 4),
    array('id' => 105, 'bid' => 0.3, 'priority' => 5),
    array('id' => 106, 'bid' => 0.3, 'priority' => 5),
    array('id' => 107, 'bid' => 0.2, 'priority' => 5),
    array('id' => 108, 'bid' => 0.7, 'priority' => 5),
    array('id' => 108, 'bid' => 0.1, 'priority' => 4)
);
function cmp(&$a, &$b) {                                     # notice the use of & in function signature
    if ($a['bid'] - $b['bid']) {
        return $a['bid'] - $b['bid'] > 0 ? 1 : -1;           # bid is different, sort using bid
    } else if ($a['priority'] - $b['priority']) {
        return $a['priority'] - $b['priority'] > 0 ? 1 : -1; # priority is different, sort using priority
    } else {
        if (isset($a['rw']) == false) {
            $a['rw'] = rand(1, 100);                         # assign random tie breaker
        } 
        if (isset($b['rw']) == false) {
            $b['rw'] = rand(1, 100);                         # assign random tie breaker
        } 
        if ($a['rw'] - $b['rw']) {
            return $a['rw'] - $b['rw'] > 0 ? 1 : -1;         # sort using random weight
        } else {
            return 0;
        }
    }
}
usort($array, 'cmp');
var_dump($array);

Output

array(9) {
[0]=>array(3) {["id"]=>int(108) ["bid"]=>float(0.1) ["priority"]=>int(4)}
[1]=>array(3) {["id"]=>int(107) ["bid"]=>float(0.2) ["priority"]=>int(5)}
[2]=>array(4) {["id"]=>int(106) ["bid"]=>float(0.3) ["priority"]=>int(5) ["rw"]=>int(70)}
[3]=>array(4) {["id"]=>int(105) ["bid"]=>float(0.3) ["priority"]=>int(5) ["rw"]=>int(73)}
[4]=>array(4) {["id"]=>int(103) ["bid"]=>float(0.4) ["priority"]=>int(4) ["rw"]=>int(29)}
[5]=>array(4) {["id"]=>int(104) ["bid"]=>float(0.4) ["priority"]=>int(4) ["rw"]=>int(67)}
[6]=>array(4) {["id"]=>int(102) ["bid"]=>float(0.4) ["priority"]=>int(4) ["rw"]=>int(80)}
[7]=>array(3) {["id"]=>int(101) ["bid"]=>float(0.5) ["priority"]=>int(5)}
[8]=>array(3) {["id"]=>int(108) ["bid"]=>float(0.7) ["priority"]=>int(5)}
}
Community
  • 1
  • 1
Salman A
  • 262,204
  • 82
  • 430
  • 521
1

Usort would be ideal for this situation http://www.php.net/manual/en/function.usort.php
You define the function that does the comparisons

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

usort($data, "cmp");
?>
Waygood
  • 2,657
  • 2
  • 15
  • 16
1

You can use usort

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

            if ($a['id'] == $b['id']) {
                if ($a['priority'] == $b['priority'] && $a['bid'] == $b['bid']) {
                    $pos = array(-1,0,1);
                    return $pos[mt_rand(0, 2)]; // shurffle
                }

                $a = $a['priority'];
                $b = $b['priority'];

                return ($a == $b) ? 0 : (($a > $b) ? - 1 : 1); // sorty by priority
            }

            // First i need to sort based on bid
            $a = $a['id'];
            $b = $b['id'];
            return ($a == $b) ? 0 : (($a < $b) ? - 1 : 1); //sort by bid id
    });
Baba
  • 94,024
  • 28
  • 166
  • 217
  • isnt the first check a typo? The `id` should be `bid` i guess? – Hugo Delsing May 07 '13 at 08:28
  • Its not .. its an if statement .. it would only run if `id` is the same if not it would use the id for sorting .... can be a little confusing but look at it one more time – Baba May 07 '13 at 08:42
  • I guess the comments you added threw me off. The comments mention `bid` while the code mentions `id` – Hugo Delsing May 07 '13 at 08:54
1

Also based on @Hugos answer, adding shuffle using PHP built in shuffle() and range() functions:

<?php
$data=array(

array('id'=>101,'bid'=>0.5,'priority'=>5),
array('id'=>102,'bid'=>0.4,'priority'=>4),
array('id'=>103,'bid'=>0.4,'priority'=>4),
array('id'=>104,'bid'=>0.4,'priority'=>4),
array('id'=>105,'bid'=>0.3,'priority'=>5),
array('id'=>106,'bid'=>0.3,'priority'=>5),
array('id'=>107,'bid'=>0.2,'priority'=>5),
array('id'=>108,'bid'=>0.7,'priority'=>5),
array('id'=>108,'bid'=>0.1,'priority'=>4)
);


$rand=range(0,count($data)-1);
shuffle($rand);

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

array_multisort($bid, SORT_ASC, $prio, SORT_ASC, $rand, SORT_ASC, $data);

I first tried simply shuffling the array before sorting, but for some unknown reason, sorting seems to sort on id as well. Probably some effect of algorithm used.

Community
  • 1
  • 1
Atle
  • 5,299
  • 1
  • 15
  • 10
0
<?php

foreach ($data as $key => $row) {
  //just create a random field
  $data[$key]['randSort']= rand(1,999999);
  $sameRand[$key] = $data[$key]['randSort'];

  $bid[$key]  = $row['bid'];
  $prio[$key] = $row['priority'];
}

array_multisort($bid, SORT_ASC, $prio, SORT_ASC, $sameRand, SORT_ASC, $data);
?>
-1
  • put elements to be shuffled into an array and remove them from the initial array until the initial array is empty.
  • call shuffle on the created array
  • put the shuffled array into a new array with the results.
Adder
  • 5,708
  • 1
  • 28
  • 56