Advanced ordering of items in an array

2

I have an advanced report, which ultimately sorts the items based on your score:

// Variável $relatório contém dados levantados e calculados em blocos para N itens. Cada bloco possui uma pontuação total do mesmo.
//  Ex: $relatorio[0]['consolidado']['bloco_1']['total_pontos'],  $relatorio[0]['consolidado']['bloco_2']['total_pontos'], $relatorio[0]['consolidado']['bloco_3']['total_pontos'], $relatorio[0]['consolidado']['bloco_N']['total_pontos'], ...

$classificacao_items = array();
foreach ($relatorio as $relatorio_item) {
    $classificacao_items[] = array(
        'cod_item' => $relatorio_item['item']['cod_item'],
        'item' => $relatorio_item['item']['descricao'],
        'etapa_num' => $relatorio_item['consolidado']['etapa_num'], // etapa_num é um índice do relatório consolidado que recebe um valor de 0 a 5 (varia de acordo com média de metas atingidas do item)
        'pontos' => $relatorio_item['consolidado']['total_pontos'],
    );
}

Currently, I raise the sorting using multisort of the array

$classificacao_items = array_orderby($classificacao_items, 'etapa_num', SORT_ASC, 'pontos', SORT_DESC, 'item', SORT_ASC);

As you can see, I first sort by etapa_num , then by pontos and last by item (Item name, alphabetical).

Function snippet:

/**
 * Função de ordenação de arrays
 * @see http://www.php.net/manual/en/function.array-multisort.php#100534
 * @return mixed
 */
function array_orderby() {
    $args = func_get_args();
    $data = array_shift($args);
    foreach ($args as $n => $field) {
        if (is_string($field)) {
            $tmp = array();
            foreach ($data as $key => $row)
                $tmp[$key] = $row[$field];
            $args[$n] = $tmp;
        }
    }
    $args[] = &$data;

    call_user_func_array('array_multisort', $args);

    return array_pop($args);
}

What I need now: If there is a tie of points, I need to examine the sum of blocks (1 and 2 in the case) of the items and give a better ranking for an item (adding blocks 1 and 2), since the current parameter would be his name. That is: you would need to apply a custom function.

My problem is that I can not successfully apply this custom function. It ends up detonating the organization of items already correctly classified.

// Variável $items == variável $relatorio (descrito acima na introdução), ou seja, apenas com outro "apelido"
usort($classificacao_items, function($a, $b) use ($items) {
    if ($a['pontos'] != $b['pontos']) // na lógica quando retorna 0 não é pra modificar a posição do item
        return 0;

    $relatorio_a = $items[$a['cod_item']]['consolidado'];
    $relatorio_b = $items[$b['cod_item']]['consolidado'];

    $notas_a = $relatorio_a['bloco_1']['total_pontos'] + $relatorio_a['bloco_2']['total_pontos'];
    $notas_b = $relatorio_b['bloco_1']['total_pontos'] + $relatorio_b['bloco_2']['total_pontos'];

    return $notas_a  > $notas_b ? 1 : -1;
});

At the moment, I can not see a workable solution to my problem. Every approach I try, I end up disorganizing with the order of the array. I need to apply this tiebreaker function only in cases where the punctuation is the same and does not change what is right (with more or less punctuation).

    
asked by anonymous 24.03.2015 / 20:27

1 answer

4

Can not put all sorting logic into the custom method?

usort($classificacao_items, function($a, $b) use ($items) {

    // 'etapa_num', SORT_ASC
    if ($a['etapa_num'] < $b['etapa_num']) return -1;
    if ($a['etapa_num'] > $b['etapa_num']) return 1;

    // 'pontos', SORT_DESC
    if ($a['pontos'] > $b['pontos']) return -1;
    if ($a['pontos'] < $b['pontos']) return 1;

    // 'item', SORT_ASC
    if ($a['item'] < $b['item']) return -1;
    if ($a['item'] > $b['item']) return 1;

    $relatorio_a = $items[$a['cod_item']]['consolidado'];
    $relatorio_b = $items[$b['cod_item']]['consolidado'];

    $notas_a = $relatorio_a['bloco_1']['total_pontos'] + $relatorio_a['bloco_2']['total_pontos'];
    $notas_b = $relatorio_b['bloco_1']['total_pontos'] + $relatorio_b['bloco_2']['total_pontos'];

    if ($notas_a < $notas_b) return -1;
    if ($notas_a > $notas_b) return 1;

    return 0;
});
    
24.03.2015 / 20:52