Como classificar a matriz multidimensional por valor?


1129

Como posso classificar essa matriz pelo valor da chave "order"? Mesmo que os valores sejam atualmente seqüenciais, eles nem sempre serão.

Array
(
    [0] => Array
        (
            [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
            [title] => Flower
            [order] => 3
        )

    [1] => Array
        (
            [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
            [title] => Free
            [order] => 2
        )

    [2] => Array
        (
            [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
            [title] => Ready
            [order] => 1
        )
)


a maneira mais rápida é usar o módulo de matriz de classificação isomórfica que funciona nativamente no navegador e no nó, suportando qualquer tipo de entrada, campos calculados e ordens de classificação personalizadas.
Lloyd

Respostas:


1734

Experimente um usort , se você ainda está no PHP 5.2 ou anterior, terá que definir uma função de classificação primeiro:

function sortByOrder($a, $b) {
    return $a['order'] - $b['order'];
}

usort($myArray, 'sortByOrder');

A partir do PHP 5.3, você pode usar uma função anônima:

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

E, finalmente, com o PHP 7, você pode usar o operador de nave espacial :

usort($myArray, function($a, $b) {
    return $a['order'] <=> $b['order'];
});

Para estender isso à classificação multidimensional, faça referência aos segundo / terceiro elementos de classificação, se o primeiro for zero - melhor explicado abaixo. Você também pode usar isso para classificar subelementos.

usort($myArray, function($a, $b) {
    $retval = $a['order'] <=> $b['order'];
    if ($retval == 0) {
        $retval = $a['suborder'] <=> $b['suborder'];
        if ($retval == 0) {
            $retval = $a['details']['subsuborder'] <=> $b['details']['subsuborder'];
        }
    }
    return $retval;
});

Se você precisar manter associações de teclas, use uasort()- consulte a comparação das funções de classificação de matriz no manual


2
Meu fraseado está um pouco fora, eu vou editá-lo. O que eu quis dizer é que, se você não está no PHP 5.3, precisa criar uma função especial apenas para essa classificação específica (que de alguma forma não é muito elegante). Caso contrário, você poderia usar uma função anônima ali.
Christian Studer

23
@ Jonathan: Você realmente não consegue ver a maior parte do trabalho que o PHP faz. Ele pega a matriz e começa com dois elementos, que foram passados ​​para essa função definida pelo usuário. Sua função é responsável por compará-los: se o primeiro elemento for maior que o segundo, retorne um número inteiro positivo; se for menor, retorne um número negativo. Se eles são iguais, retorne 0. O PHP envia outros dois elementos para sua função e continua a fazê-lo, até que a matriz tenha sido classificada. A função aqui é muito curta, pode ser muito mais complicada se você não estiver comparando números inteiros.
Christian Studer

61
Protip: use uasort()se você deseja preservar as chaves da matriz.
thaddeusmt

15
Cuidado se os valores classificáveis ​​forem números decimais. Se a função de classificação obtiver $ a = 1 e $ b = 0,1, a diferença será 0,9, mas a função retornará um int, nesse caso 0, então $ a e $ b serão considerados iguais e classificados incorretamente. É mais confiável comparar se $ a é maior que $ b ou igual e retornar -1, 1 ou 0 de acordo.
11593 Greenlandi

37
Levei um tempo para descobrir. Para classificar a ordem inversa (DESC), você pode alternar entre $ a e $ b. Então $ b ['order'] - $ a ['order']
JanWillem 02/02

285
function aasort (&$array, $key) {
    $sorter=array();
    $ret=array();
    reset($array);
    foreach ($array as $ii => $va) {
        $sorter[$ii]=$va[$key];
    }
    asort($sorter);
    foreach ($sorter as $ii => $va) {
        $ret[$ii]=$array[$ii];
    }
    $array=$ret;
}

aasort($your_array,"order");

7
@ noc2spam Estou feliz em ajudar, mas considere seguir a sugestão do aluno, que provavelmente é mais eficiente e certamente mais arrumada!
o0 '.

1
@ Lohoris certeza cara, eu estou verificando isso também. Ontem teria sido um dia mais difícil no escritório se eu não encontrar esta pergunta :-)
Gogol

hmm não posso adicionar uma resposta .. bem, eu coloquei aqui porque eu não preciso desses pontos estúpidos: então, para um tipo multidimensional, é (quase) a mesma coisa (srry, você precisa copiar e colar e reformatá-lo): function aasort (& $ array , $ key1, $ key2, $ key3) {$ classificador = array (); $ ret = array (); reset ($ array); foreach ($ array como $ ii => $ va) {$ classificador [$ ii] = getPrice ($ va [$ key1] [$ key2] [$ key3]); } arsort ($ classificador); foreach ($ classificador como $ ii => $ va) {$ ret [$ ii] = $ array [$ ii]; } $ array = $ ret; }
Jaxx0rr

3
Muito mais fácil de aplicar do que a resposta acima
Marcel

1
VOCÊ É DEMAIS!! Funciona como encanto para PHP 7.2 Muito obrigado CARO :)
Kamlesh

270

Eu uso esta função:

function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) {
    $sort_col = array();
    foreach ($arr as $key=> $row) {
        $sort_col[$key] = $row[$col];
    }

    array_multisort($sort_col, $dir, $arr);
}


array_sort_by_column($array, 'order');

3
Funciona muito bem. A solução exclusiva é capaz de adicionar uma direção de classificação. Obrigado!
Ivo Pereira

2
Para uma alternativa que suporta instruções de classificação e muitos recursos adicionais, você pode dar uma olhada na minha resposta aqui - ela também tem a vantagem de não ser usada array_multisorte, portanto, não precisa pré-alocar $sort_col, economizando tempo e memória .
28413 Jon

Funciona muito bem para mim, mas ... por que é necessário especificar em &$arrvez de apenas $arr?
Radu Murzea

2
@RaduMurzea assim a matriz é passada por referência e pode ser modificado pela função, em vez do que a função de receber uma cópia
Tom Haigh

1
@AdrianP. : A matriz é passada por referência para que ele irá modificar a matriz passada em vez de retornar uma cópia ordenada
Tom Haigh

72

Eu normalmente uso usort e passo minha própria função de comparação. Nesse caso, é muito simples:

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

No PHP 7, usando o operador de nave espacial:

usort($array, function($a, $b) {
    return $a['order'] <=> $b['order'];
});

4
Droga, eu estava 30 segundos mais lento. Não é $ a - $ b?
Christian Studer

3
Eu sempre entendi errado. Deixe-me pensar no manual: o valor de retorno deve ser menor que zero se o primeiro argumento for considerado menor que o segundo. Então, se $a['order']é 3 e $b['order']é 6, retornarei -3. Corrigir?
Jan Fabry

3
Bem, você retorna b - a, então será 3. E assim classificado incorretamente.
Christian Christian Studer

26
Ah ESTÁ BEM. Eu estava usando aritmética não lógica, onde a ideia na sua cabeça não corresponde às palavras que você produz. Isso é estudado com mais frequência nas tardes de sexta-feira.
Jan Fabry

em alguns casos, a resposta acima é o resultado incorreto .. referência stackoverflow.com/questions/50636981/…
Bilal Ahmed

45

Uma abordagem para conseguir isso seria assim

    $new = [
              [
                'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4',
                'title' => 'Flower',
                'order' => 3,
              ],

              [
                'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594',
                'title' => 'Free',
                'order' => 2,
              ],

              [
                'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b',
                'title' => 'Ready',
                'order' => 1,
              ],
    ];

    $keys = array_column($new, 'order');

    array_multisort($keys, SORT_ASC, $new);

    var_dump($new);

Resultado:

    Array
    (
        [0] => Array
            (
                [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
                [title] => Ready
                [order] => 1
            )

        [1] => Array
            (
                [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
                [title] => Free
                [order] => 2
            )

        [2] => Array
            (
                [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
                [title] => Flower
                [order] => 3
            )

    )

18

Para classificar a matriz pelo valor da chave "title", use:

uasort($myArray, function($a, $b) {
    return strcmp($a['title'], $b['title']);
});

strcmp compara as strings.

uasort () mantém as chaves da matriz como elas foram definidas.


strcmp é uma ajuda notável para os tipos varchar, gostei desta resposta de forma rápida e rápida
StudioX 27/03

17
$sort = array();
$array_lowercase = array_map('strtolower', $array_to_be_sorted);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);

Isso cuida dos alfabetos maiúsculas e minúsculas.


4
Como isso responde à questão da classificação por uma chave de matriz específica?
Seano 16/08/16

12

Use array_multisort(),array_map()

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

print_r($array);

DEMO


Observe que essa abordagem emitirá um aviso. array_multisortreferencia seu primeiro parâmetro.
Kami Yang

5

A abordagem mais flexível seria usar esse método

Arr::sortByKeys(array $array, $keys, bool $assoc = true): array

aqui está o porquê:

  • Você pode classificar por qualquer chave (também aninhada como 'key1.key2.key3'ou ['k1', 'k2', 'k3'])

  • Funciona em matrizes associativas e não associativas ( $assocsinalizador)

  • Ele não usa referência - retorna uma nova matriz classificada

No seu caso, seria tão simples quanto:

$sortedArray = Arr::sortByKeys($array, 'order');

Este método faz parte desta biblioteca .


1

Vamos ser sinceros: o php NÃO possui uma função simples e pronta para lidar adequadamente com todos os cenários de classificação de array.

Essa rotina é intuitiva, o que significa depuração e manutenção mais rápidas:

// automatic population of array
$tempArray = array();
$annotations = array();
// ... some code
// SQL $sql retrieves result array $result 
// $row[0] is the ID, but is populated out of order (comes from 
// multiple selects populating various dimensions for the same DATE 
// for example
while($row = mysql_fetch_array($result)) {
    $needle = $row[0];
    arrayIndexes($needle);  // create a parallel array with IDs only
    $annotations[$needle]['someDimension'] = $row[1]; // whatever
}
asort($tempArray);
foreach ($tempArray as $arrayKey) {
    $dataInOrder = $annotations[$arrayKey]['someDimension']; 
    // .... more code
}

function arrayIndexes ($needle) {
    global $tempArray;
    if (!in_array($needle,$tempArray)) {
        array_push($tempArray,$needle);
    }
}

4
"Vamos ser sinceros: o php NÃO possui uma função simples e pronta para lidar adequadamente com todos os cenários de classificação de matrizes." Isso é exatamente o que usort / ksort / asort são projetados para ^^'
Ben Cassinat

3
Na verdade, o PHP tem muitas funções de classificação que podem ser usadas para lidar com todos os cenários de classificação de array.
axiac 29/05

No que diz respeito à depuração e manutenção, o uso de globalé uma enorme bandeira vermelha e geralmente é desencorajado . Por que está mysql_fetch_arraysendo demonstrado para esta pergunta em vez da matriz de origem do OP, e que não há explicação do que seu código está fazendo e do que se pode esperar que o resultado seja? No geral, essa é uma abordagem muito complexa para alcançar o resultado final desejado.
Fyrye 01/05/19

@tonygil Não consigo determinar quais são os resultados esperados da sua resposta e do conjunto de dados do OP. Pode ser óbvio para você, mas não sei como sua resposta responde à pergunta do OP. No entanto, você pode passar por referência em vez de usar globalver: 3v4l.org/FEeFC Isso produz uma variável definida explicitamente, em vez de uma que pode ser alterada e acessada globalmente.
Fyrye 02/05/19

0

Você também pode classificar a matriz multidimensional para vários valores, como

$arr = [
    [
        "name"=> "Sally",
        "nick_name"=> "sal",
        "availability"=> "0",
        "is_fav"=> "0"
    ],
    [
        "name"=> "David",
        "nick_name"=> "dav07",
        "availability"=> "0",
        "is_fav"=> "1"
    ],
    [
        "name"=> "Zen",
        "nick_name"=> "zen",
        "availability"=> "1",
        "is_fav"=> "0"
    ],
    [
        "name"=> "Jackson",
        "nick_name"=> "jack",
        "availability"=> "1",
        "is_fav"=> "1"
    ],
    [
        "name"=> "Rohit",
        "nick_name"=> "rod",
        "availability"=> "0",
        "is_fav"=> "0"
    ],

];

com

usort($arr,function($a,$b){
    $c = $b['is_fav'] - $a['is_fav'];
    $c .= $b['availability'] - $a['availability'];
    $c .= strcmp($a['nick_name'],$b['nick_name']);
    return $c;
});

Saída usando print_r($arr):

Array
(
    [0] => Array
        (
            [name] => Jackson
            [nick_name] => jack
            [availability] => 1
            [is_fav] => 1
        )

    [1] => Array
        (
            [name] => David
            [nick_name] => dav07
            [availability] => 0
            [is_fav] => 1
        )

    [2] => Array
        (
            [name] => Zen
            [nick_name] => zen
            [availability] => 1
            [is_fav] => 0
        )

    [3] => Array
        (
            [name] => Rohit
            [nick_name] => rod
            [availability] => 0
            [is_fav] => 0
        )

    [4] => Array
        (
            [name] => Sally
            [nick_name] => sal
            [availability] => 0
            [is_fav] => 0
        )

)

PS) usando strcmp seria uma boa opção para comparar as strings.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.