Home > Mobile >  Sort data in column of a multi-dimensional array in a descending direction while preserving keys
Sort data in column of a multi-dimensional array in a descending direction while preserving keys

Time:12-01

I have the following array that I'm attempting to sort each scores array by answer from high to low.

$array = [
    503 => [
        'scores' => [
            4573 => ['answer' => 100],
            4574 => ['answer' => 60],
            4575 => ['answer' => 100],
            4576 => ['answer' => 80],
            4577 => ['answer' => 40],
            4578 => ['answer' => 20],
            4579 => ['answer' => 60],
            4580 => ['answer' => 100],
            4581 => ['answer' => 60],
            4582 => ['answer' => 60],
            4583 => ['answer' => 80],
            4584 => ['answer' => 80],
        ],
        'category' => 'Category A',
        'grade' => 70,
        'color' => NULL
    ],
    504 => [
        'scores' => [
            4585 => ['answer' => 40],
            4586 => ['answer' => 100],
            4587 => ['answer' => 80],
            4588 => ['answer' => 60],
            4589 => ['answer' => 100],
            4590 => ['answer' => 40],
            4591 => ['answer' => 80],
            4592 => ['answer' => 60],
            4593 => ['answer' => 60],
            4594 => ['answer' => 100],
            4595 => ['answer' => 100],
            4596 => ['answer' => 80], 
        ],
        'category' => 'Category B',
        'grade' => 75,
        'color' => NULL
    ],
    505 => [
        'scores' => [
            4597 =>['answer' => 20],
            4598 =>['answer' => 80],
            4599 =>['answer' => 100],
            4600 =>['answer' => 60],
            4601 =>['answer' => 20],
            4602 =>['answer' => 20],
            4603 =>['answer' => 100],
            4604 =>['answer' => 40],
            4605 =>['answer' => 60],
            4606 =>['answer' => 100],
            4607 =>['answer' => 80],
            4608 =>['answer' => 20],
        ],
        'category' => 'Category C',
        'grade' => 58.3,
        'color' => NULL, 
    ]
];

I've attempted to use loops to get into the array level needed, but it isn't working...

$temp_array_questions = $array_categorygrades;
function sortq ($a, $b) {
    $highestcountfora = 0;
    $highestcountforb = 0;
    
    foreach ($a as $thescores) {
        if (is_array($thescores)) {
            foreach ($thescores as $thequestions) {
                if (is_array($thequestions)) {
                    foreach ($thequestions as $theanswers) {
                        if ($theanswers['answer'] > $highestcountfora) {
                            $highestcountfora = $theanswers['answer'];
                        }
                    }
                }
            }
        }
    }
    
    foreach ($b as $thescores) {
        if (is_array($thescores)) {
            foreach ($thescores as $thequestions) {
                if (is_array($thequestions)) {
                    foreach ($thequestions as $theanswers) {
                        if ($theanswers['answer'] > $highestcountforb) {
                            $highestcountforb = $theanswers['answer'];
                        }
                    }
                }
            }
        }
    }
    
    if ($highestcountfora === $highestcountforb) {
        return 0;
    }
    
    return ($highestcountfora < $highestcountforb)?1:-1;
    
    //if($a['scores']['answer']==$b['scores']['answer']) return 0;
    //return $a['scores']['answer'] < $b['scores']['answer']?1:-1;
} 
uasort($temp_array_questions, 'sortq');

The array should look like this after sorting:

[
    503 => [
        'scores' => [
            4573 => ['answer' => 100],
            4575 => ['answer' => 100],
            4580 => ['answer' => 100],
            4576 => ['answer' => 80],
            4583 => ['answer' => 80],
            4584 => ['answer' => 80],
            4574 => ['answer' => 60],
            4579 => ['answer' => 60],
            4581 => ['answer' => 60],
            4582 => ['answer' => 60],
            4577 => ['answer' => 40],
            4578 => ['answer' => 20],
        ],
        'category' => 'Category A',
        'grade' => 70,
        'color' => NULL
    ],
    504 => [
        'scores' => [
            4586 => ['answer' => 100],
            4589 => ['answer' => 100],
            4594 => ['answer' => 100],
            4595 => ['answer' => 100],
            4587 => ['answer' => 80],
            4591 => ['answer' => 80],
            4596 => ['answer' => 80],
            4588 => ['answer' => 60],
            4592 => ['answer' => 60],
            4593 => ['answer' => 60],
            4585 => ['answer' => 40],
            4590 => ['answer' => 40],
        ],
        'category' => 'Category B',
        'grade' => 75,
        'color' => NULL
    ],
    505 => [
        'scores' => [
            4599 =>['answer' => 100],
            4603 =>['answer' => 100],
            4606 =>['answer' => 100],
            4598 =>['answer' => 80],
            4607 =>['answer' => 80],
            4600 =>['answer' => 60],
            4605 =>['answer' => 60],
            4604 =>['answer' => 40],
            4597 =>['answer' => 20],
            4601 =>['answer' => 20],
            4602 =>['answer' => 20],
            4608 =>['answer' => 20],
        ],
        'category' => 'Category C',
        'grade' => 58.3,
        'color' => NULL,
    ]
]

CodePudding user response:

Just use usort for each individual array of scores:

foreach ($data as $key => $item) {
  if (!isset($item["scores"])) continue;
 
  $scores = $item["scores"];
  usort($scores, function($a, $b) {
    return $a["answer"] - $b["answer"];
  });

  $data[$key]["scores"] = $scores;

}


CodePudding user response:

Sort the scores subsets by their answer value by calling asort() on each subset.

I am using "array destructuring" to access only the scores subsets and & to modify the input array by reference.

You do not need to explicitly mention answer elements because they are lone elements in their respective subarray. By default, PHP will sort by array size, then by values; because each subarray only has one element (size = 1), the sort will fallback to the answer value.

Code: (Sort ASC Demo) (Sort DESC Demo)

foreach ($array as ['scores' => &$scores]) {
    arsort($scores);  // or asort($scores) for ascending sorting
}
var_export($array);
  • Related