PHP Classificar Array Por Valor de SubArray

110

Eu tenho a seguinte estrutura de array:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )

Qual é a melhor maneira de ordenar o array de forma incremental, com base no optionNumber?

Portanto, os resultados são parecidos com:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )
Sjwdavies
fonte

Respostas:

204

Use usort.

function cmp_by_optionNumber($a, $b) {
  return $a["optionNumber"] - $b["optionNumber"];
}

...

usort($array, "cmp_by_optionNumber");

No PHP ≥5.3, você deve usar uma função anônima em seu lugar:

usort($array, function ($a, $b) {
    return $a['optionNumber'] - $b['optionNumber'];
});

Observe que ambos os códigos acima assumem $a['optionNumber']ser um número inteiro. Use @St. A solução de John Johnson se forem cordas.


No PHP ≥7.0, use o operador<=> da nave espacial em vez da subtração para evitar problemas de estouro / truncamento.

usort($array, function ($a, $b) {
    return $a['optionNumber'] <=> $b['optionNumber'];
});
Kennytm
fonte
1
Isso realmente não me ajuda, pois o usort exige que eu forneça uma função para usar - que é a parte difícil que não consigo entender
Sjwdavies,
17
Bem, ele apenas lhe deu a função para usar. E você vai ter que aceitar que nem sempre há uma função embutida para fazer o que você quer, você mesmo tem que escrever. As funções de comparação requerem apenas um retorno de 1, 0 ou -1, indicando a ordem de classificação para dois elementos.
Tesserex
1
Eu pesquisei mais sobre o usort e ele é muito legal. Escrevi uma função de comparação simples com a acima, mas perdi o '=='. Obrigado pela ajuda pessoal
Sjwdavies
3
Agora também como encerramento: - usort ($ array, function ($ a, $ b) {return $ b ["optionNumber"] - $ a ["optionNumber"];});
Joeri
1
@ KiloumapL'artélon Se o resultado for < 0, indica a função de classificação que adeve aparecer antes b. Se for, > 0então bdeve aparecer antes a.
kennytm
57

Usar usort

 usort($array, 'sortByOption');
 function sortByOption($a, $b) {
   return strcmp($a['optionNumber'], $b['optionNumber']);
 }
St. John Johnson
fonte
7
@BenSinclair, isso porque a solução de Kenny é para números, essa solução é para strings. Ambos estão corretos :-) +1 para esta alternativa.
kubilay
Para classificação sem distinção entre maiúsculas e minúsculas, use strcasecmp em vez de strcmp
user570605
podemos definir a chave para a segunda ordem no array significa que primeiro classificamos com optionNumber e depois classificamos com lastUpdated. Como posso fazer isso?
Bhavin Thummar de
16

Eu usei ambas as soluções KennyTM e AJ Quick e vim com uma função que pode ajudar neste problema para muitos casos, como usar ASC ou DESC classificando ou preservando chaves ou se você tiver objetos como filhos de array .

Aqui está esta função (funciona para PHP7 e superior por causa do operador de nave espacial):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if ($preserveKeys) {
        $c = [];
        if (is_object(reset($array))) {
            foreach ($array as $k => $v) {
                $b[$k] = strtolower($v->$value);
            }
        } else {
            foreach ($array as $k => $v) {
                $b[$k] = strtolower($v[$value]);
            }
        }
        $asc ? asort($b) : arsort($b);
        foreach ($b as $k => $v) {
            $c[$k] = $array[$k];
        }
        $array = $c;
    } else {
        if (is_object(reset($array))) {
            usort($array, function ($a, $b) use ($value, $asc) {
                return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
            });
        } else {
            usort($array, function ($a, $b) use ($value, $asc) {
                return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
            });
        }
    }

    return $array;
}

Uso:

sortBySubValue($array, 'optionNumber', true, false);

Editar

A primeira parte pode ser reescrita usando uasort()e a função será mais curta (funciona para PHP7 e superior por causa do operador de nave espacial):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if (is_object(reset($array))) {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        });
    } else {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        });
    }
    return $array;
}
Pigalev Pavel
fonte
Esta é a melhor resposta mais útil aqui, deve estar no topo;)
Edi Budimilic
@EdiBudimilic obrigado, agradeço! A propósito, atualizei minha resposta e adicionei uma versão mais curta desta função :)
Pigalev Pavel
1
Para fazer isso funcionar para mim, tive que usar >(maior que) em vez de -(menos) ao comparar os valores $ae $b, já que estava comparando strings. Ainda funciona.
James
1
@James você está certo. Mudei a resposta e adicionei o uso do operador de nave espacial (<=>). Agora deve funcionar bem.
Pigalev Pavel
Existe uma maneira de tornar este caso insensível?
loeffel
4

As teclas são removidas ao usar uma função como as acima. Se as chaves forem importantes, a função a seguir manterá isso ... mas os loops foreach são bastante ineficientes.

function subval_sort($a,$subkey) {
    foreach($a as $k=>$v) {
        $b[$k] = strtolower($v[$subkey]);
    }
    asort($b);
    foreach($b as $key=>$val) {
        $c[$key] = $a[$key];
    }
    return $c;
}
$array = subval_sort($array,'optionNumber');

Use arsort em vez de asort se quiser de alto para baixo.

Crédito do código: http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/

AJ Quick
fonte
4

Usando array_multisort (), array_map ()

array_multisort(array_map(function($element) {
      return $element['optionNumber'];
  }, $array), SORT_ASC, $array);

print_r($array);

DEMO

Ghanshyam Nakiya
fonte
2
Isso funciona muito facilmente. Obrigado. Tudo que eu tive que fazer foi mudar o nome da minha coluna e funcionou.
Kobus Myburgh
2
Isso também preserva as chaves da matriz pai
JonnyS
3

PHP 5.3+

usort($array, function($a,$b){ return $a['optionNumber']-$b['optionNumber'];} );
Samer Ata
fonte