1

I tried lot of tricks and googling to solve this problem but couldn't get the useful stuff.

Basically following is the content of an element from an associative array(exam result of candidates and I've to give ranking to the candidates) which contains several such elements.

I want to sort the array in ascending order depending on the key [total_obtained_marks] i.e. candidate having more marks will be first ranked,

then if same values find I've to sort the array in descending order based on key [no_wrong_answers] i.e. less no. of wrong answers.

Even if the rank remains same I've to sort the array in ascending order of the key [test_user_time_used] i.e. the candidate with less time used will get higher rank.

Even then the ranks are same then I've to sort the array on the key [user_first_name] in ascending order i.e alphabetically.

After doing all this stuff I could get the well sorted array which will have proper ranking for candidates.

One more thing about this unsorted array is no actual data could be sorted from the database, so database functions can't be used.

Whatever has to be done will be on this unsorted array itself. Please help me out to solve this issue. Thanks in Advance. Name of the associative array is $test_result.

Array
(
    [14ddcea23dfc46bed4f2a15da7901c51] => Array
        (
            [test_user_data] => Array
                (
                    [test_user_id] => 6297
                    [test_user_user_id] => 14ddcea23dfc46bed4f2a15da7901c51
                    [test_user_test_id] => 348
                    [user_first_name] => Shahin
                    [user_last_name] => Khan
                    [user_name] => Shahin Khan
                    [test_user_status] => present
                    [test_user_time_used] => 00:00:00 Hr
                    [test_user_start_time] => 1356514472
                    [test_duration] => 4500
                    [test_name] => NEET: Electrostatics 1
                    [test_mode] => non-schedule
                    [test_end_time] => 0
                    [user_status] => Attempted
                )

            [test_question_data] => Array
                (
                    [73101] => Array
                        (
                            [question_text] => If a glass rod is rubbed with silk it acquires a positive charge because :
                            [question_file] => 
                            [correct_ans_text] => electrons are removed from it
                            [correct_ans_file] => 
                            [correct_ans_id] => 291299
                            [user_marked_ans_text] => electrons are removed from it
                            [user_marked_ans_file] => 
                            [user_marked_ans_id] => 291299
                        )

                    [77101] => Array
                        (
                            [question_text] => In a charged capacitor , the energy is stored in :
                            [question_file] => 
                            [correct_ans_text] => the field between the plates
                            [correct_ans_file] => 
                            [correct_ans_id] => 307468
                            [user_marked_ans_text] => the field between the plates
                            [user_marked_ans_file] => 
                            [user_marked_ans_id] => 307468
                        )

                    [75069] => Array
                        (
                            [question_text] => ABC is right-angle triangle with sides AB = 3 cm, BC = 4 cm, AC = 5 cm, charges 15, 12 and -20 respectively. Magnitude of the force experienced by the charge at B in dynes is :<br>
<img alt="\&quot;\&quot;" src="\&quot;http://www.entranceprime.com/upload_media/questions/original/1338456478_10.jpg\&quot;" height="\&quot;169\&quot;" width="\&quot;228\&quot;">
                            [question_file] => 
                            [correct_ans_text] => 25
                            [correct_ans_file] => 
                            [correct_ans_id] => 299192
                            [user_marked_ans_text] => 25
                            [user_marked_ans_file] => 
                            [user_marked_ans_id] => 299192
                        )

                    [77526] => Array
                        (
                            [question_text] => The work done in increasing the coltage across the plates of a capacitor from 5 V to 10 V is W. The work done in increasing the voltage from 10 V to 15 V will be :
                            [question_file] => 
                            [correct_ans_text] => W
                            [correct_ans_file] => 
                            [correct_ans_id] => 578079
                            [user_marked_ans_text] => W
                            [user_marked_ans_file] => 
                            [user_marked_ans_id] => 578079
                        )

                    [73190] => Array
                        (
                            [question_text] => Select the corrent alternative :
                            [question_file] => 
                            [correct_ans_text] => Charge cannot exist without matter although matter can exist without charge
                            [correct_ans_file] => 
                            [correct_ans_id] => 291651
                            [user_marked_ans_text] => Charge cannot exist without matter although matter can exist without charge
                            [user_marked_ans_file] => 
                            [user_marked_ans_id] => 291651
                        )

                    [127452] => Array
                        (
                            [question_text] => Capacity of a conductor depends upon
                            [question_file] => 
                            [correct_ans_text] => size of conductor <br>
                            [correct_ans_file] => 
                            [correct_ans_id] => 510229
                            [user_marked_ans_text] => all of these<br>
                            [user_marked_ans_file] => 
                            [user_marked_ans_id] => 510232
                        )

                    [127503] => Array
                        (
                            [question_text] => A charged spherical shell does not produce an electric field at any
                            [question_file] => 
                            [correct_ans_text] => interior point <br>
                            [correct_ans_file] => 
                            [correct_ans_id] => 510425
                            [user_marked_ans_text] => interior point <br>
                            [user_marked_ans_file] => 
                            [user_marked_ans_id] => 510425
                        )

                    [75631] => Array
                        (
                            [question_text] => A solid conducting sphere having a charge Q is surrounded by an uncharged concentric conducting hollow spherical shell. Let the potential difference between the surface of the solid sphere and that of the outer surface of the hollow shell be V . If the shell is now given a charge -3q , the new potential difference between the same two surface is :
                            [question_file] => 
                            [correct_ans_text] => V
                            [correct_ans_file] => 
                            [correct_ans_id] => 301488
                            [user_marked_ans_text] => 
                            [user_marked_ans_file] => 
                            [user_marked_ans_id] => 
                        )

                )

            [subject_wise_result] => Array
                (
                    [5] => Array
                        (
                            [subject_id] => 5
                            [subject_name] => 12 PHYSICS
                            [no_correct_answers] => 6
                            [no_wrong_answers] => 1
                            [no_skipped_questions] => 38
                            [total_obtained_marks] => 23
                            [total_questions] => 45
                            [total_percent] => 100 %
                            [gain_percent] => 12.78 % 
                        )

                )

            [test_result_data] => Array
                (
                    [no_correct_answers] => 6
                    [no_wrong_answers] => 1
                    [no_skipped_questions] => 38
                    [total_obtained_marks] => 23
                )

        )
    )
inhan
  • 7,038
  • 1
  • 20
  • 35
PHPLover
  • 7,021
  • 32
  • 90
  • 182
  • 2
    Argh, format your posts :| – Jonnix Jan 09 '13 at 15:55
  • @JonStirling. I'm a newbie to PHP. I've used the print_r() function to show the array and put the content of one of its element. – PHPLover Jan 09 '13 at 15:57
  • 2
    The whole post is one big splodge of text. It's very hard to read like that. Format it into paragraphs; more people will take time to read it if it's broken into smaller bits. And then for the `print_r()` bit, use "view source" and copy+paste that rather than the unformatted version shown in the browser. – SDC Jan 09 '13 at 15:58
  • 1
    Ways to get not-crap formatting: 1. Encapsulate the `print_r()` output in `
    ` tags. 2. Copy the output from the page source. 3. Run it from the command line.
    – Sammitch Jan 09 '13 at 16:03
  • 1
    @SDC As per your suggestion I've done the proper formatting. Now you could get the better idea of the scenario. Thanks for your suggestion. I'll keep in mind next time. – PHPLover Jan 09 '13 at 16:07
  • much better :) (though not sure why it's html-encoded; print_r doesn't do that by default). (and also the body text could still do with splitting into paragraphs) – SDC Jan 09 '13 at 16:08
  • possible duplicate of [PHP sort an array of array](http://stackoverflow.com/questions/3449889/php-sort-an-array-of-array) – Niet the Dark Absol Jan 09 '13 at 16:13
  • Also a duplicate of http://stackoverflow.com/questions/2978447/how-to-sort-an-array-of-arrays-in-php, http://stackoverflow.com/questions/7239783/array-sorting-in-php, http://stackoverflow.com/questions/5200385/sort-array-in-php and basically all questions in a [search for "php sort array of arrays"](http://stackoverflow.com/search?q=php+sort+array+of+arrays). – Niet the Dark Absol Jan 09 '13 at 16:14
  • @Sammitch: Why HTML `
    ` tags? We use _Markdown_ here on SO. Please read the formatting FAQ.
    – Lightness Races in Orbit Jan 09 '13 at 16:18
  • @LightnessRacesinOrbit not on SO, in his code. The only way I know of to get `print_r()` output looking the way he originally posted it is to output it to dump it out into HTML *without* `
    ` tags.
    – Sammitch Jan 09 '13 at 16:34
  • @Sammitch: Oh, right. :) Well he ought to have "View Source"d in any case. – Lightness Races in Orbit Jan 09 '13 at 16:51

2 Answers2

7

PHP provides quite a few functions for sorting arrays. In this case, the one you want is uasort(), which sorts an array according to a user-defined comparison function while maintaining key-value associations:

function compare_results ( $a, $b ) {
    $diff = strcmp( $a['test_user_data']['user_status'],
                    $b['test_user_data']['user_status'] );
    if ( $diff != 0 ) return $diff < 0 ? -1 : 1;  // ascending order
    // ("Attempted" < "Not attempted")

    $diff = $a['test_result_data']['total_obtained_marks'] -
            $b['test_result_data']['total_obtained_marks'];
    if ( $diff != 0 ) return $diff > 0 ? -1 : 1;  // descending order

    $diff = $a['test_result_data']['no_wrong_answers'] -
            $b['test_result_data']['no_wrong_answers'];
    if ( $diff != 0 ) return $diff < 0 ? -1 : 1;  // ascending order

    $diff = strcmp( $a['test_user_data']['test_user_time_used'],
                    $b['test_user_data']['test_user_time_used'] );
    if ( $diff != 0 ) return $diff < 0 ? -1 : 1;  // ascending order

    $diff = strcmp( $a['test_user_data']['user_name'],
                    $b['test_user_data']['user_name'] );
    if ( $diff != 0 ) return $diff < 0 ? -1 : 1;  // ascending order

    return 0;  // give up, they're as good as equal
}

uasort( $test_result, compare_results );

Writing such comparison functions is (briefly) documented on the usort() function documentation page.

Note, in particular, the warning about non-integer return values being truncated, which is why I'm returning $diff < 0 ? -1 : 1 rather than just $diff itself. In your case, this shouldn't matter, since the numeric values appear to be integers, but it could cause hard-to-find bugs if the system was ever modified to allow, say, partial marks to be awarded. Thus, always returning either -1, 0 or 1 from comparison functions is a good habit to get into.

(For the string comparisons, the $diff < 0 ? -1 : 1 is doubly pointless, since strcmp() is documented to always return -1, 0 or 1 anyway, but I've used it there also for the sake of consistency. It doesn't really do any harm, and as I said, it's a good habit to get into.)

Also note that I'm comparing the time values as strings. If this does not yield the results you're expecting, you'll need to write your own time comparison code.

Ps. If you're using PHP 5.3.0 or later, you can also write the comparison function as an anonymous function, like this:

uasort( $test_result, function ( $a, $b ) {
    // function body goes here
} );
Ilmari Karonen
  • 44,762
  • 9
  • 83
  • 142
  • Thank you so much Ilmari Karonen for understanding and solving my problem. Your code did the required magic, I got the sorted array as I wanted. Thank you once again for your valuable help. – PHPLover Jan 09 '13 at 19:04
  • I've a small problem with the sorted associative array. There are few elements in the associative array whose [user_status] is having value 'Not Attempted' like this [user_status] => Not Attempted. I want to put all such array elements at the bottom of sorted array after the elements whose value is [user_status] => Attempted. What code should I write to make the sorted array better? Can anyone help please? Thanks in Advance. – PHPLover Jan 10 '13 at 11:03
  • 1
    If those are the only possible values, you could just sort the records first based on the `user_status` value. (I just edited my answer to do that, see above.) If you need something more complicated (e.g. if the rules for sorting the "Not Attempted" users should be different than those for the "Attempted" ones) then the same principle still applies: first check if one of `$a` and `$b` is "Not Attempted" and the other "Attempted", and if so, return -1 or +1 depending on which is which; otherwise, compare the other fields as appropriate. – Ilmari Karonen Jan 10 '13 at 20:49
  • 1
    Or, alternatively, you could just make two copies of the array, remove the "Not Attempted" users from one copy and the "Attempted" ones from the other using [`array_filter()`](http://php.net/array_filter), then sort each copy separately and add them together with [`+`](http://php.net/manual/en/language.operators.array.php) or with [`array_merge()`](http://php.net/array_merge). – Ilmari Karonen Jan 10 '13 at 20:53
  • Thank you very much @Ilmari Karonen. The change you did in the code did the required magic for me. Also your valuable suggestions helped me to get the fully sorted associative array. Thanks once again. – PHPLover Jan 11 '13 at 06:10
0

You need to define your own compare function and sort the array using usort().

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

usort($array, 'cmp');
Seain Malkin
  • 2,213
  • 17
  • 19