I have a data structure that look like this
$data = [ [ "name" => "user_a", "code" => "c1", "description" => "criteria 1", "type" => "benefit", "weight" => 25, "value" => 75 ], [ "name" => "user_a", "code" => "c2", "description" => "criteria 2", "type" => "benefit", "weight" => 20, "value" => 67 ], [ "name" => "user_a", "code" => "c3", "description" => "criteria 3", "type" => "benefit", "weight" => 15, "value" => 80 ], [ "name" => "user_a", "code" => "c4", "description" => "criteria 4", "type" => "benefit", "weight" => 22, "value" => 90 ], [ "name" => "user_a", "code" => "c5", "description" => "criteria 5", "type" => "benefit", "weight" => 8, "value" => 20 ], [ "name" => "user_a", "code" => "c6", "description" => "criteria 6", "type" => "benefit", "weight" => 10, "value" => 80 ], [ "name" => "user_b", "code" => "c1", "description" => "criteria 1", "type" => "benefit", "weight" => 25, "value" => 65 ], [ "name" => "user_b", "code" => "c2", "description" => "criteria 2", "type" => "benefit", "weight" => 20, "value" => 70 ], [ "name" => "user_b", "code" => "c3", "description" => "criteria 3", "type" => "benefit", "weight" => 15, "value" => 80 ], [ "name" => "user_b", "code" => "c4", "description" => "criteria 4", "type" => "benefit", "weight" => 22, "value" => 90 ], [ "name" => "user_b", "code" => "c5", "description" => "criteria 5", "type" => "benefit", "weight" => 8, "value" => 20 ], [ "name" => "user_b", "code" => "c6", "description" => "criteria 6", "type" => "benefit", "weight" => 10, "value" => 80 ], ];
I’m trying to get the normalized values but it wasn’t giving me the expected result with my current algorithm.
// This one is fine $matrix_x = get_matrix_x($data); // result: [ // "user_a": [75, 67, 80, 90, 20, 80], // "user_b": [65, 70, 80, 90, 20, 80], // "user_c": [56, 70, 75, 80, 50, 70], // ]; // This one is producing the wrong result (I rounded it just to make it readable, decimals are OK to be shown as is) $matrix_r = get_matrix_r($data, $matrix_x); // current result: [ // "user_a": [0.8, 0.7, 0.8, 1.0, 0.2, 0.8], // "user_b": [0.7, 0.7, 0.8, 1.0, 0.2, 0.8], // "user_c": [0.7, 0.8, 0.9, 1.0, 0.6, 0.8], // ]; // expected result: [ // "user_a": [1.0, 0.9, 1.0, 1.0, 0.4, 1.0], // "user_b": [0.8, 1.0, 1.0, 1.0, 0.4, 1.0], // "user_c": [0.7, 1.0, 0.9, 0.8, 1.0, 0.8], // ];
I have been stuck with this problem for about 4 days, the problem is in the min(...)
and max(...)
function inside the get_matrix_r
method. It was supposed to take the number from top to bottom for each column instead of taking the highest/lowest number directly from the key given by $matrix_x
but I don’t know how to do that.
I also asked a question related to this issue, but when I loop inside the $reducer
using the given solutions, it produce extra items in the result. Please help!
functions.php
/** * Generate matrix_x from the given data. * * @param array $data * @param string $key * @param string $valkey * @return array */ function get_matrix_x(array $data, string $key = 'name', string $valkey = 'value') { $reducer = function ($acc, $item) use ($key, $valkey) { $index = $item[$key]; if (!isset($acc[$index])) { $acc[$index] = []; } $acc[$index][] = (int) $item[$valkey]; return $acc; }; return array_reduce($data, $reducer, []); } /** * Generate matrix_r from data and matrix_x as origin. * * @param array $data * @param array $origin * @param string $key * @param string $valkey * @param string $compkey * @return array */ function get_matrix_r(array $data, array $origin, string $key = 'name', string $valkey = 'value', string $compkey = 'type') { $reducer = function ($acc, $item) use ($key, $valkey, $origin, $compkey) { $index = $item[$key]; if (!isset($acc[$index])) { $acc[$index] = []; } $item[$compkey] === 'cost' ? $acc[$index][] = (int) $item[$valkey] / min($origin[$index]) : $acc[$index][] = (int) $item[$valkey] / max($origin[$index]); return $acc; }; return array_reduce($data, $reducer, []); }
Advertisement
Answer
Well, the first problem, is that in the dataset you are providing there is not user_c
, but in the output matrix there are references to that, so that’s weird.
The second problem, is that in the reducer, you are considering the ROWs, and not the COLUMNs… to consider those, you should do something like this:
/** * Generate matrix_r from data and matrix_x as origin. * * @param array $data * @param array $origin * @param string $key * @param string $valkey * @param string $compkey * @return array */ function get_matrix_r(array $data, array $origin, string $key = 'name', string $valkey = 'value', string $compkey = 'type') { $reducer = function ($acc, $item) use ($key, $valkey, $origin, $compkey) { $index = $item[$key]; print_r($item); if (!isset($acc[$index])) { $acc[$index] = []; } // consider the nth COLUMN, with $origin[$index] you was considering the ROW $col = array_column($origin, count($acc[$index])); $item[$compkey] === 'cost' ? $acc[$index][] = (int) $item[$valkey] / min($col) : $acc[$index][] = (int) $item[$valkey] / max($col); return $acc; }; return array_reduce($data, $reducer, []); }