-1

Let us suppose I have an array like below

    $item = Array(

             [0] => Array(
                     "name" => "item1"
                     "score" => 100,
                     "category" => "A1",
                     "vote"  => 80,
               )

          [1] => Array(
                 "name" => "item2",
                 "score" => 100,
                 "category" => "A1",
                 "vote"    => 70,
           )
           [2] => Array(
                 "name" => "item3",
                 "score" => 80,
                 "category" => "A2",
                 "vote"    => 80,
           )
           [3] => Array(
                 "name" => "item4",
                 "score" => 80,
                 "category" => "A2",
                 "vote"    => 60,
           )
           [4] => Array(
                 "name" => "item5",
                 "score" => 80,
                 "category" => "A3",
                 "vote"    => 80,
           )
    )

edited input:

    Array
(
    [0] => Array
        (
            [name] => item1
            [score] => 100
            [category] => A1
            [vote] => 80
        )

    [1] => Array
        (
            [name] => item2
            [score] => 100
            [category] => A1
            [vote] => 80
        )

    [2] => Array
        (
            [name] => item5
            [score] => 80
            [category] => A3
            [vote] => 80
        )

    [3] => Array
        (
            [name] => item3
            [score] => 80
            [category] => A2
            [vote] => 80
        )

    [4] => Array
        (
            [name] => item4
            [score] => 80
            [category] => A2
            [vote] => 60
        )

)

The priority of the sort is score, category and vote consequently. The expected result is :

$item = Array(

             [0] => Array(
                     "name" => "item1"
                     "score" => 100,
                     "category" => "A1",
                     "vote"    => 80,
               )
            [1] => Array(
                 "name" => "item5",
                 "score" => 80,
                 "category" => "A3",
                 "vote"    => 80,
            )
            [2] => Array(
                 "name" => "item3",
                 "score" => 80,
                 "category" => "A2",
                 "vote"    => 80,
           )

          [3] => Array(
                 "name" => "item2",
                 "score" => 100,
                 "category" => "A1",
                 "vote"    => 70,
           )

           [4] => Array(
                 "name" => "item4",
                 "score" => 80,
                 "category" => "A2",
                 "vote"    => 60,
           )

    )

edited expected result:

   Array
    (
    [0] => Array
        (
            [name] => item1
            [score] => 100
            [category] => A1
            [vote] => 80
        )

    [1] => Array
        (
            [name] => item5
            [score] => 80
            [category] => A3
            [vote] => 80
        )

    [2] => Array
        (
            [name] => item3
            [score] => 80
            [category] => A2
            [vote] => 80
        )
   [3] => Array
        (
            [name] => item2
            [score] => 100
            [category] => A1
            [vote] => 80
        )

    [4] => Array
        (
            [name] => item4
            [score] => 80
            [category] => A2
            [vote] => 60
        )

)

I want to have the distinct categories at the top sorted based on the score and then vote but if they are two items with the same category, the item with the lower score will have lower priority.

Based on the insight from , I first sort the array based on score, category and vote

foreach($list as $k=>$v) {
        $sorted['score'][$k] = $v['score'];
        $sorted['category'][$k] = $v['category'];
        $sorted['vote'][$k] = $v['vote'];
    }

    array_multisort($sorted['score'], SORT_DESC, $sorted['category'], SORT_DESC,$sorted['vote'], SORT_DESC, $list);

It will give me:

    Array
(
    [0] => Array
        (
            [name] => item1
            [score] => 100
            [category] => A1
            [vote] => 80
        )

    [1] => Array
        (
            [name] => item2
            [score] => 100
            [category] => A1
            [vote] => 80
        )

    [2] => Array
        (
            [name] => item5
            [score] => 80
            [category] => A3
            [vote] => 80
        )



  [3] => Array
        (
            [name] => item3
            [score] => 80
            [category] => A2
            [vote] => 80
        )
    [4] => Array
        (
            [name] => item4
            [score] => 80
            [category] => A2
            [vote] => 60
        )

)

I need to re-sort the result again to have the distinct categories at the top (see the edited expected result)

Edited: It seems my example and question are confusing. The idea is I want to sort the item based on the score and then vote but the category should be taken into consideration. On top of score and vote, I want to have the time with the distinct categories on top and then the score and vote follow.

Priska Aprilia
  • 1,149
  • 1
  • 15
  • 34
  • 1
    You must define a comparison function and use usort() http://stackoverflow.com/questions/24559050/sort-array-using-multiple-criteria-in-php – viktor77 Oct 09 '15 at 16:39
  • I have [answered a similar question](http://stackoverflow.com/questions/31990237/re-order-an-arrays-items-based-on-several-criteria/31993715#31993715) and my answer was accepted, see if adapting it works for you – al'ein Oct 09 '15 at 16:43
  • i'm a bit confuse, which is you priority is the score is high but the vote is low? – 0yeoj Oct 10 '15 at 07:32
  • the score is preferable that the vote. vote is the second priority. But the category should be taken into consideration. But on top of that I want to have distinct(different) categories as the priority first then the score and vote follow as mentioned above. – Priska Aprilia Oct 10 '15 at 07:38
  • okay.. i have a suggestion though, why don't you sort them by category first then have a sorting for both votes and scores? and make life a little easier? – 0yeoj Oct 10 '15 at 09:05

2 Answers2

1

use array_multisort()

<?php
$mylist = Array(

             0 => Array(
                     "name" => "item1",
                     "score" => 100,
                     "category" => "A1",
                     "vote"  => 80
               ),

          1 => Array(
                 "name" => "item2",
                 "score" => 100,
                 "category" => "A1",
                 "vote"    => 70
           ),
           2 => Array(
                 "name" => "item3",
                 "score" => 80,
                 "category" => "A2",
                 "vote"    => 80
           ),
           3 => Array(
                 "name" => "item4",
                 "score" => 80,
                 "category" => "A2",
                 "vote"    => 60
           ),
           4 => Array(
                 "name" => "item5",
                 "score" => 80,
                 "category" => "A3",
                 "vote"    => 80
           )
    );

$sort = array();
foreach($mylist as $k=>$v) {
    $sort['score'][$k] = $v['score'];
    $sort['category'][$k] = $v['category'];
    $sort['vote'][$k] = $v['vote'];
}
# sort by event_type desc and then title asc
array_multisort($sort['vote'], SORT_DESC,$sort['score'], SORT_DESC, $sort['category'], SORT_DESC,$mylist);
    echo '<pre>';
    print_r($mylist);
    echo '</pre>';
?>
Payer Ahammed
  • 887
  • 1
  • 5
  • 16
0

NOTE: This is not an answer, this is just a suggestion. suppose to be a comment but there are codes and it's quite long.

First i just revamped your input array to this model:

enter image description here

Using this code:

$compiled = array();

for ($i = 0; $i < count($input_arr); $i++)
{
    $cat = $input_arr[$i]['category'];

    $index = count($compiled[$cat]);

    $compiled[$cat][$index]['name'] = $input_arr[$i]['name'];
    $compiled[$cat][$index]['score'] = $input_arr[$i]['score'];
    $compiled[$cat][$index]['vote'] = $input_arr[$i]['vote'];
    $compiled[$cat][$index]['overall'] = $input_arr[$i]['score'] + $input_arr[$i]['vote'];
}

I just arranged it by category. And also i added overall it's just the sum of score and vote. :)

All the sorting comes here:

foreach ($compiled as $k => $v)
{
    $json['sorted_by_vote'][$k] = sort_sub_value($compiled[$k], 'vote', false);

    $json['sorted_by_score'][$k] = sort_sub_value($compiled[$k], 'score', false);

    for ($i = 0;$i < count($compiled[$k]); $i++)
    {
        $json['sorted_by_overall'][] = $compiled[$k][$i];
    }
}
$json['sorted_by_overall'] = sort_sub_value($json['sorted_by_overall'], 'overall', false);

$json['input'] = $input_arr;

$json['revamp'] = $compiled;

echo json_encode($json);

function sort_sub_value($array, $subkey, $is_asc = true)
{
    foreach($array as $k=>$v) 
    {
        $b[$k] = strtolower($v[$subkey]);
    }

    if ($is_asc)
        asort($b); // asort -> asc | arsort ->desc
    else
        arsort($b);

    foreach($b as $key=>$val) 
    {
        $c[] = $array[$key];
    }
    return $c;
}

and will produce this:

enter image description here

enter image description here

enter image description here

And lastly here's the sample input i just mess with the votes to test.

enter image description here

Hope this would be helpful for some other reason. Cheers brother! :)

0yeoj
  • 4,500
  • 3
  • 23
  • 41