Como posso ordenar matrizes e dados em PHP?

292

Esta questão é uma referência para perguntas sobre a classificação de matrizes em PHP. É fácil pensar que seu caso em particular é único e digno de uma nova pergunta, mas a maioria é na verdade pequenas variações de uma das soluções desta página.

Se sua pergunta for encerrada como duplicada, solicite que ela seja reaberta apenas se você puder explicar por que ela difere significativamente de todas as opções abaixo.

Como faço para classificar uma matriz em PHP?
Como faço para classificar uma matriz complexa em PHP?
Como faço para classificar uma matriz de objetos em PHP?


  1. Matrizes unidimensionais básicas; Incl. Matrizes multidimensionais, incl. matrizes de objetos; Incl. Classificando uma matriz com base em outra

  2. Classificando com SPL

  3. Classificação estável

Para a resposta prática usando as funções existentes do PHP, consulte 1., para a resposta acadêmica em detalhes sobre algoritmos de classificação (que funções do PHP implementam e que você pode precisar para casos realmente complexos), consulte 2.

deceze
fonte
@ jterry Exatamente, é por isso que eu fiz isso para finalmente ter uma boa pergunta de referência para fechar. Responder a cada floco de neve exclusivo individualmente não ajuda ninguém. :)
deceze
3
Acho que as pessoas devem simplesmente dar uma olhada em php.net
Alexander Jardim
@Alex Ha! Absolutamente. O problema é: ninguém RTFM. : D
deceze
2
Já temos essas respostas, sugiro que você vincule as melhores respostas de cada resposta aqui em vez de duplicar (ou reescrever) o conteúdo. Também as matrizes tendem a ser vistas individualmente, de modo que o trabalho permanece em votação fechada contra os burros em qualquer caso.
hakre
1
@deceze: Se ninguém RTFM, ninguém vai também RTFQA - o existente Q & A :)
hakre

Respostas:

164

Matrizes unidimensionais básicas

$array = array(3, 5, 2, 8);

Funções de classificação aplicáveis:

  • sort
  • rsort
  • asort
  • arsort
  • natsort
  • natcasesort
  • ksort
  • krsort

A diferença entre eles é apenas se as associações de valor-chave são mantidas (as " a" funções), se classifica de baixo para alto ou reverso (" r"), se classifica valores ou chaves (" k") e como compara valores (" nat" vs. normal). Veja http://php.net/manual/en/array.sorting.php para uma visão geral e links para mais detalhes.

Matrizes multidimensionais, incluindo matrizes de objetos

$array = array(
    array('foo' => 'bar', 'baz' => 42),
    array('foo' => ...,   'baz' => ...),
    ...
);

Se você deseja classificar $arraypela tecla 'foo' de cada entrada, precisa de uma função de comparação personalizada . As sortfunções acima e relacionadas funcionam com valores simples que eles sabem comparar e classificar. O PHP simplesmente não "sabe" o que fazer com um valor complexo como esse array('foo' => 'bar', 'baz' => 42); então você precisa contar.

Para fazer isso, você precisa criar uma função de comparação . Essa função usa dois elementos e deve retornar 0se esses elementos forem considerados iguais, um valor menor que 0se o primeiro valor for menor e um valor maior que 0se o primeiro valor for maior. É tudo o que é necessário:

function cmp(array $a, array $b) {
    if ($a['foo'] < $b['foo']) {
        return -1;
    } else if ($a['foo'] > $b['foo']) {
        return 1;
    } else {
        return 0;
    }
}

Freqüentemente, você desejará usar uma função anônima como retorno de chamada. Se você deseja usar um método ou método estático, consulte as outras maneiras de especificar um retorno de chamada no PHP .

Você então usa uma destas funções:

Novamente, eles diferem apenas se mantêm associações de valores-chave e classificam por valores ou chaves. Leia a documentação deles para obter detalhes.

Exemplo de uso:

usort($array, 'cmp');

usortpegará dois itens da matriz e chamará sua cmpfunção com eles. Assim cmp()será chamado com $acomo array('foo' => 'bar', 'baz' => 42)e $bcomo outro array('foo' => ..., 'baz' => ...). A função então retorna para usortqual dos valores foi maior ou se eles foram iguais. usortrepete esse processo passando valores diferentes para $ae $baté que a matriz seja classificada. A cmpfunção será chamada muitas vezes, pelo menos quantas vezes houver valores $array, com diferentes combinações de valores para $ae $bsempre.

Para se acostumar com essa ideia, tente o seguinte:

function cmp($a, $b) {
    echo 'cmp called with $a:', PHP_EOL;
    var_dump($a);
    echo 'and $b:', PHP_EOL;
    var_dump($b);
}

Tudo o que você fez foi definir uma maneira personalizada de comparar dois itens, é tudo o que você precisa. Isso funciona com todos os tipos de valores.

A propósito, isso funciona com qualquer valor, os valores não precisam ser matrizes complexas. Se você deseja fazer uma comparação personalizada, também pode fazê-lo em uma matriz simples de números.

sort classifica por referência e não retorna nada útil!

Observe que a matriz é classificada no local , não é necessário atribuir o valor de retorno a nada. $array = sort($array)substituirá a matriz por true, não por uma matriz classificada. Apenas sort($array);funciona.

Comparações numéricas personalizadas

Se você deseja classificar pela bazchave, que é numérica, tudo que você precisa fazer é:

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

Graças ao valor de MATH, isso retorna um valor <0, 0 ou> 0, dependendo de se $aé menor que, igual ou maior que $b.

Observe que isso não funcionará bem para floatvalores, pois eles serão reduzidos a uma inte perderão precisão. Use explícita -1, 0e 1valores de retorno em seu lugar.

Objetos

Se você possui uma matriz de objetos, funciona da mesma maneira:

function cmp($a, $b) {
    return $a->baz - $b->baz;
}

Funções

Você pode fazer qualquer coisa dentro de uma função de comparação, incluindo funções de chamada:

function cmp(array $a, array $b) {
    return someFunction($a['baz']) - someFunction($b['baz']);
}

Cordas

Um atalho para a primeira versão de comparação de cadeias:

function cmp(array $a, array $b) {
    return strcmp($a['foo'], $b['foo']);
}

strcmpé exatamente o que se espera cmpaqui, ele retorna -1, 0ou 1.

Operador de nave espacial

O PHP 7 introduziu o operador de nave espacial , que unifica e simplifica igual / menor / maior que as comparações entre os tipos:

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

Classificando por vários campos

Se você deseja classificar principalmente por foo, mas se foofor igual para dois elementos, classifique por baz:

function cmp(array $a, array $b) {
    if (($cmp = strcmp($a['foo'], $b['foo'])) !== 0) {
        return $cmp;
    } else {
        return $a['baz'] - $b['baz'];
    }
}

Para aqueles familiarizados, isso é equivalente a uma consulta SQL com ORDER BY foo, baz.
Veja também esta versão simplificada e simples de como criar uma função de comparação dinamicamente para um número arbitrário de chaves .

Classificando em uma ordem estática manual

Se você deseja classificar os elementos em uma "ordem manual", como "foo", "bar", "baz" :

function cmp(array $a, array $b) {
    static $order = array('foo', 'bar', 'baz');
    return array_search($a['foo'], $order) - array_search($b['foo'], $order);
}

Por todas as razões acima, se você estiver usando PHP 5.3 ou superior (e realmente deveria), use funções anônimas para obter um código mais curto e evitar que outra função global flutue:

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

É assim que a classificação de uma matriz multidimensional complexa pode ser simples. Novamente, pense em termos de ensinar PHP como saber qual dos dois itens é "maior" ; deixe o PHP fazer a classificação real.

Também para todas as opções acima, para alternar entre ordem crescente e decrescente, basta trocar os argumentos $ae $b. Por exemplo:

return $a['baz'] - $b['baz']; // ascending
return $b['baz'] - $a['baz']; // descending

Classificando uma matriz com base em outra

E há o peculiar array_multisort, que permite classificar um array com base em outro:

$array1 = array( 4,   6,   1);
$array2 = array('a', 'b', 'c');

O resultado esperado aqui seria:

$array2 = array('c', 'a', 'b');  // the sorted order of $array1

Use array_multisortpara chegar lá:

array_multisort($array1, $array2);

A partir do PHP 5.5.0, você pode usar array_columnpara extrair uma coluna de uma matriz multidimensional e classificar a matriz nessa coluna:

array_multisort(array_column($array, 'foo'), SORT_DESC, $array);

A partir do PHP 7.0.0, você também pode extrair propriedades de uma matriz de objetos.


Se você tiver casos mais comuns, sinta-se à vontade para editar esta resposta.

deceze
fonte
A função de comparação numérica não funciona para valores flutuantes; Eu estou certo que você sabe o que quero dizer :)
Jack
1
Para a ordem estática, eu aplicaria array_flip()para fazer uma pesquisa de posição mais rápida, por exemplo, em $order[$a['foo']]vez de array_search($a['foo'], $order).
Ja͢ck
Pode ser uma grande edição: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b, mas se você acha que é uma melhoria e eu incluí tudo o que é essencial, posso aplicá-la.
Rizier123
@ Rizier123 Eu certamente aplaudo o esforço, é uma redação muito boa; mas eu preferiria que você a publicasse como resposta separada, mesmo que seja muito semelhante. Sua reescrita contém muitos detalhes (passagem por referência, tabela grande etc.), mas esse detalhe distrai da introdução suave ao tópico principal do funcionamento da função de comparação, IMHO. Eu me refiro explicitamente ao manual várias vezes de propósito, porque é onde esses detalhes devem ser pesquisados; não é necessário repeti-lo aqui e desviar a atenção da idéia central que estou tentando transmitir.
deceze
@deceze O principal desafio, uma vez que é uma questão de perguntas e respostas, é exibir as informações o mais compactas e legíveis possível e facilitar a localização das funções de classificação pelos usuários. Eu tweaked algumas coisas: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b mas eu ainda tenho que pensar sobre isso, se é útil e valioso para publicá-la como resposta em separado, uma vez que é um conteúdo muito semelhante
Rizier123
139

Bem, a maioria dos métodos básicos já está coberta por deceze. Eu tentaria olhar para outros tipos de tipos.

Classificando com SPL

SplHeap

class SimpleHeapSort extends SplHeap {
    public function compare($a, $b) {
        return strcmp($a, $b);
    }
}

// Let's populate our heap here (data of 2009)
$heap = new SimpleHeapSort();
$heap->insert("a");
$heap->insert("b");
$heap->insert("c");

echo implode(PHP_EOL, iterator_to_array($heap));

Resultado

c
b
a

SplMaxHeap

A classe SplMaxHeap fornece as principais funcionalidades de um heap, mantendo o máximo no topo.

$heap = new SplMaxHeap();
$heap->insert(1);
$heap->insert(2);
$heap->insert(3);

SplMinHeap

A classe SplMinHeap fornece as principais funcionalidades de um heap, mantendo o mínimo no topo.

$heap = new SplMinHeap ();
$heap->insert(3);
$heap->insert(1);
$heap->insert(2);

Outros tipos de classificação

Tipo de bolha

Do artigo da Wikipedia sobre Bubble Sort:

A classificação por bolha, às vezes incorretamente chamada de classificação por afundamento, é um algoritmo de classificação simples que funciona repetidamente percorrendo a lista a ser classificada, comparando cada par de itens adjacentes e trocando-os se estiverem na ordem errada. A passagem pela lista é repetida até que não sejam necessários swaps, o que indica que a lista está classificada. O algoritmo recebe seu nome da maneira como os elementos menores "borbulham" até o topo da lista. Como ele usa comparações apenas para operar em elementos, é um tipo de comparação. Embora o algoritmo seja simples, a maioria dos outros algoritmos de classificação é mais eficiente para grandes listas.

function bubbleSort(array $array) {
    $array_size = count($array);
    for($i = 0; $i < $array_size; $i ++) {
        for($j = 0; $j < $array_size; $j ++) {
            if ($array[$i] < $array[$j]) {
                $tem = $array[$i];
                $array[$i] = $array[$j];
                $array[$j] = $tem;
            }
        }
    }
    return $array;
}

Classificação da seleção

A partir do artigo da Wikipedia sobre tipo de seleção:

Na ciência da computação, a classificação por seleção é um algoritmo de classificação, especificamente uma classificação de comparação no local. Possui complexidade de tempo O (n2), tornando-o ineficiente em listas grandes e geralmente apresenta desempenho pior que o tipo de inserção semelhante. A classificação por seleção é notada por sua simplicidade e possui vantagens de desempenho em relação a algoritmos mais complicados em determinadas situações, particularmente onde a memória auxiliar é limitada.

function selectionSort(array $array) {
    $length = count($array);
    for($i = 0; $i < $length; $i ++) {
        $min = $i;
        for($j = $i + 1; $j < $length; $j ++) {
            if ($array[$j] < $array[$min]) {
                $min = $j;
            }
        }
        $tmp = $array[$min];
        $array[$min] = $array[$i];
        $array[$i] = $tmp;
    }
    return $array;
}

Classificação de inserção

No artigo da Wikipedia sobre Inserção, classifique:

A classificação por inserção é um algoritmo de classificação simples que cria a matriz (ou lista) final classificada um item por vez. É muito menos eficiente em listas grandes do que algoritmos mais avançados, como quicksort, heapsort ou merge sort. No entanto, a classificação por inserção oferece várias vantagens:

function insertionSort(array $array) {
    $count = count($array);
    for($i = 1; $i < $count; $i ++) {

        $j = $i - 1;
        // second element of the array
        $element = $array[$i];
        while ( $j >= 0 && $array[$j] > $element ) {
            $array[$j + 1] = $array[$j];
            $array[$j] = $element;
            $j = $j - 1;
        }
    }
    return $array;
}

Shellsort

Do artigo da Wikipedia sobre Shellsort:

O Shellsort, também conhecido como classificação do Shell ou método da Shell, é um tipo de comparação no local. Ele generaliza uma classificação de troca, como inserção ou classificação de bolha, iniciando a comparação e troca de elementos com elementos distantes antes de terminar com elementos vizinhos.

function shellSort(array $array) {
    $gaps = array(
            1,
            2,
            3,
            4,
            6
    );
    $gap = array_pop($gaps);
    $length = count($array);
    while ( $gap > 0 ) {
        for($i = $gap; $i < $length; $i ++) {
            $tmp = $array[$i];
            $j = $i;
            while ( $j >= $gap && $array[$j - $gap] > $tmp ) {
                $array[$j] = $array[$j - $gap];
                $j -= $gap;
            }
            $array[$j] = $tmp;
        }
        $gap = array_pop($gaps);
    }
    return $array;
}

Classificação de pente

A partir do artigo da Wikipedia sobre Comb tipo:

A classificação pente é um algoritmo de classificação relativamente simples, originalmente projetado por Wlodzimierz Dobosiewicz em 1980. Mais tarde, foi redescoberto por Stephen Lacey e Richard Box em 1991. A classificação pente melhora a classificação por bolhas.

function combSort(array $array) {
    $gap = count($array);
    $swap = true;
    while ( $gap > 1 || $swap ) {
        if ($gap > 1)
            $gap /= 1.25;
        $swap = false;
        $i = 0;
        while ( $i + $gap < count($array) ) {
            if ($array[$i] > $array[$i + $gap]) {
                // swapping the elements.
                list($array[$i], $array[$i + $gap]) = array(
                        $array[$i + $gap],
                        $array[$i]
                );
                $swap = true;
            }
            $i ++;
        }
    }
    return $array;
}

Mesclar classificação

A partir do artigo da Wikipedia sobre merge sort:

Na ciência da computação, uma classificação por mesclagem (também denominada mesclagem comum) é um algoritmo de classificação baseado em comparação O (n log n). A maioria das implementações produz uma classificação estável, o que significa que a implementação preserva a ordem de entrada de elementos iguais na saída classificada

function mergeSort(array $array) {
    if (count($array) <= 1)
        return $array;

    $left = mergeSort(array_splice($array, floor(count($array) / 2)));
    $right = mergeSort($array);

    $result = array();

    while ( count($left) > 0 && count($right) > 0 ) {
        if ($left[0] <= $right[0]) {
            array_push($result, array_shift($left));
        } else {
            array_push($result, array_shift($right));
        }
    }
    while ( count($left) > 0 )
        array_push($result, array_shift($left));

    while ( count($right) > 0 )
        array_push($result, array_shift($right));

    return $result;
}

Ordenação rápida

Do artigo da Wikipedia sobre o Quicksort:

Quicksort, ou classificação de troca de partição, é um algoritmo de classificação desenvolvido por Tony Hoare que, em média, faz comparações O (n log n) para classificar n itens. Na pior das hipóteses, faz comparações de O (n2), embora esse comportamento seja raro.

function quickSort(array $array) {
    if (count($array) == 0) {
        return $array;
    }
    $pivot = $array[0];
    $left = $right = array();
    for($i = 1; $i < count($array); $i ++) {
        if ($array[$i] < $pivot) {
            $left[] = $array[$i];
        } else {
            $right[] = $array[$i];
        }
    }
    return array_merge(quickSort($left), array(
            $pivot
    ), quickSort($right));
}

Classificação de permutação

A partir do artigo da Wikipedia sobre Permutation tipo:

Classificação de permutação, que continua gerando as possíveis permutações da matriz / lista de entrada até descobrir a ordenada.

function permutationSort($items, $perms = array()) {
    if (empty($items)) {
        if (inOrder($perms)) {
            return $perms;
        }
    } else {
        for($i = count($items) - 1; $i >= 0; -- $i) {
            $newitems = $items;
            $newperms = $perms;
            list($foo) = array_splice($newitems, $i, 1);
            array_unshift($newperms, $foo);
            $res = permutationSort($newitems, $newperms);
            if ($res) {
                return $res;
            }
        }
    }
}

function inOrder($array) {
    for($i = 0; $i < count($array); $i ++) {
        if (isset($array[$i + 1])) {
            if ($array[$i] > $array[$i + 1]) {
                return False;
            }
        }
    }
    return True;
}

Classificação Radix

A partir do artigo da Wikipedia sobre Radix tipo:

Na ciência da computação, a classificação radix é um algoritmo de classificação inteira não comparativo que classifica dados com chaves inteiras, agrupando as chaves pelos dígitos individuais que compartilham a mesma posição e valor significativos.

// Radix Sort for 0 to 256
function radixSort($array) {
    $n = count($array);
    $partition = array();

    for($slot = 0; $slot < 256; ++ $slot) {
        $partition[] = array();
    }

    for($i = 0; $i < $n; ++ $i) {
        $partition[$array[$i]->age & 0xFF][] = &$array[$i];
    }

    $i = 0;

    for($slot = 0; $slot < 256; ++ $slot) {
        for($j = 0, $n = count($partition[$slot]); $j < $n; ++ $j) {
            $array[$i ++] = &$partition[$slot][$j];
        }
    }
    return $array;
}
Baba
fonte
4
@deceze você cobriu todos os princípios básicos .. eu tive que procurar outra maneira de ser relevante :)
Baba
5
Não vejo nada de errado com os métodos de classificação mais acadêmicos :) muito menos úteis para a maioria dos aplicativos, mas ocasionalmente podem ser solicitados / necessários. É útil ter uma referência, especialmente porque eu esqueci a maioria deles ao longo do tempo
Dave
Na verdade, para uma classificação rápida, recomenda-se selecionar o pivô como uma mediana de três valores: primeiro, meio e último elemento . Este é o meu exemplo para a seleção de pivô. Isso permite evitar pior caso leque reverso-ordenada (que faz com que O(n^2)as comparações se vamos usar apenas primeiro elemento como pivô)
Alma Do
Ouvi dizer que o spl funciona mais rápido que a classificação normal de matrizes.
jewelhuq
Concordo com Dave, hoje em dia, quase incluímos isso porque raramente me lembro ou o uso.
Mike Nguyen
43

Classificação estável

Digamos que você tenha uma matriz como esta:

['Kale', 'Kaleidoscope', 'Aardvark', 'Apple', 'Leicester', 'Lovely']

E agora você deseja classificar apenas na primeira letra:

usort($array, function($a, $b) {
    return strcmp($a[0], $b[0]);
});

O resultado é este:

['Apple', 'Aardvark', 'Kale', 'Kaleidoscope', 'Lovely', 'Leicester']

O tipo não era estável!

O observador aguçado pode ter notado que o algoritmo de classificação de array (QuickSort) não produziu um resultado estável e que a ordem original entre as palavras da mesma primeira letra não foi preservada. Esse caso é trivial e deveríamos ter comparado toda a cadeia de caracteres, mas vamos supor que seu caso de uso seja mais complicado, como dois tipos consecutivos em campos diferentes que não devem cancelar o trabalho um do outro.

A transformação schwartziana

A transformação Schwartziana , também chamada de idioma decorar-classificar-undecorate, efetua uma classificação estável com um algoritmo de classificação inerentemente instável.

Primeiro, você decora cada elemento da matriz com outra matriz que compreende uma chave primária (o valor) e uma chave secundária (seu índice ou posição):

array_walk($array, function(&$element, $index) {
    $element = array($element, $index); // decorate
});

Isso transforma a matriz em isso:

[
    ['Kale', 0], ['Kaleidoscope', 1], 
    ['Aardvark', 2], ['Apple', 3], 
    ['Leicester', 4], ['Lovely', 5]
]

Agora, ajustamos a etapa de comparação; comparamos a primeira letra novamente, mas, se forem iguais, a chave secundária será usada para manter a ordem original:

usort($array, function($a, $b) {
    // $a[0] and $b[0] contain the primary sort key
    // $a[1] and $b[1] contain the secondary sort key
    $tmp = strcmp($a[0][0], $b[0][0]);

    if ($tmp != 0) {
        return $tmp; // use primary key comparison results
    }

    return $a[1] - $b[1]; // use secondary key
});

Posteriormente, decoremos:

array_walk($array, function(&$element) {
    $element = $element[0];
});

O resultado final:

['Aardvark', 'Apple', 'Kale', 'Kaleidoscope', 'Leicester', 'Lovely']

E a reutilização?

Você teve que reescrever sua função de comparação para trabalhar com os elementos da matriz transformados; você pode não querer editar suas delicadas funções de comparação, então aqui está um wrapper para a função de comparação:

function stablecmp($fn)
{
    return function($a, $b) use ($fn) {
        if (($tmp = call_user_func($fn, $a[0], $b[0])) != 0) {
            return $tmp;
        } else {
            return $a[1] - $b[1];
        }
    };
}

Vamos escrever a etapa de classificação usando esta função:

usort($array, stablecmp(function($a, $b) {
    return strcmp($a[0], $b[0]);
}));

Voila! Seu código de comparação original está de volta.

Ja͢ck
fonte
Sua frase "efetua uma classificação estável com um algoritmo de classificação inerentemente instável" foi o momento ah-ha para mim. A página da Wikipedia não menciona a palavra estável, que me parece ser a beleza da transformação. Vergonha.
Tyler Collier
1
@TylerCollier Sim, você precisa ler nas entrelinhas do que a referência Wikipedia ... Salvei-lhe a dificuldade de fazer isso ;-)
Jack
15

A partir do PHP 5.3 com fechamentos, também é possível usar um fechamento para determinar a ordem de sua classificação.

Por exemplo, assumindo que $ array é uma matriz de objetos que contêm uma propriedade de mês.

 $orderArray = array("Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec");

 usort($array, function($a, $b) use ($orderArray){
       return array_search($a->month, $orderArray) - array_search($b->month, $orderArray);
 }); 
Orangepill
fonte
Lembre-se de que isso removerá qualquer ordem relativa anterior (por exemplo, o primeiro objeto "Julho" na lista pré-classificada pode terminar no final do grupo de objetos de julho após a classificação). Consulte "Classificação estável" acima.
George Langley
9

LINQ

No .NET, o LINQ é freqüentemente usado para classificação, o que fornece uma sintaxe muito mais agradável sobre as funções de comparação, especialmente quando os objetos precisam ser classificados por vários campos. Existem várias portas do LINQ para PHP, incluindo a biblioteca YaLinqo *. Com isso, as matrizes podem ser classificadas com uma única linha sem escrever funções de comparação complexas.

$sortedByName         = from($objects)->orderBy('$v->name');
$sortedByCount        = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');

As comparações podem ser personalizadas ainda mais, passando um retorno de chamada como um segundo argumento, por exemplo:

$sortedByFilenameNat  = from($objects)->orderBy('$v->filename', 'strnatcmp');

Aqui '$v->count'está uma abreviação de function ($v) { return $v->count; }(qualquer um pode ser usado). Essas cadeias de métodos retornam iteradores, os iteradores podem ser transformados em matrizes adicionando ->toArray()no final, se necessário.

Internamente, orderBye métodos relacionados chamar funções de matriz de classificação apropriados ( uasort, krsort, multisort, usortetc.).

O LINQ contém muitos outros métodos inspirados no SQL: filtragem, agrupamento, junção, agregação etc. É mais adequado para casos em que transformações complexas em matrizes e objetos precisam ser executadas sem depender de bancos de dados.

* desenvolvido por mim, consulte o leia-me para obter mais detalhes e comparação com outras portas LINQ

Athari
fonte
3

Classificação multidimensional por valor-chave

Tipo natural de uma matriz multidimensional por um valor-chave e também mantém a ordem original (não embaralhe as chaves principais):

function multisortByKeyValue( $k, $arr ) {
    $ids   = array();
    $index = 1;

    foreach ( $arr as $key => $row ) {
        $ids[ $key ] = intval( $row[ $k ] ) . '-' . $index . '-' . $key;
        $index ++;
    }

    natsort( $ids );

    $arr = array_merge( $ids, $arr );

    return $arr;
}

Caso de teste:

$arr = array(
    'id1' => array(
        'label'    => 'ID 1',
        'priority' => 30,
    ),
    'id2' => array(
        'label'    => 'ID 2',
        'priority' => 70,
    ),
    'id3' => array(
        'label'    => 'ID 3',
        'priority' => 20,
    ),
    'id4' => array(
        'label'    => 'ID 4',
        'priority' => 30,
    ),
);

$sorted = multisortByKeyValue( 'priority', $arr );

// $sorted equals to:
/*
array (
  'id3' => array (
    'label' => 'ID 3',
    'priority' => 20,
  ),
  'id1' => array (
    'label' => 'ID 1',
    'priority' => 30,
  ),
  'id4' => array (
    'label' => 'ID 4',
    'priority' => 30,
  ),
  'id2' => array (
    'label' => 'ID 2',
    'priority' => 70,
  ),
)
*/
Andrew Surdu
fonte
2

É muito conveniente classificar matrizes com a função classificada do Nspl :

Classificação básica

// Sort array
$sorted = sorted([3, 1, 2]);

// Sort array in descending order
$sortedDesc = sorted([3, 1, 2], true);

Classificando por resultado da função

// Sort array by the result of a given function (order words by length)
$sortedByLength = sorted(['bc', 'a', 'abc'], 'strlen');
$sortedByLengthDesc = sorted(['bc', 'a', 'abc'], true, 'strlen');

// Sort array by the result of user-defined function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], function($v) { return $v[0]; }); 

// Which is the same as
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], itemGetter(0));
$sortedByTheFirstCharacterDesc = sorted(['bc', 'a', 'abc'], true, itemGetter(0));

// itemGetter(0) returns a function which takes an argument with access by index/key
// and returns the value at index 0

Classificação da matriz multidimensional

// Sort multidimensional array (sort list of users by their names)
$users = [
    array('name' => 'Robert', 'age' => 20),
    array('name' => 'Alex', 'age' => 30),
    array('name' => 'Jack', 'age' => 25),
];
$sortedByName = sorted($users, itemGetter('name'));
$sortedByNameDesc = sorted($users, true, itemGetter('name'));

// itemGetter('name') returns a function which takes an argument with access by index/key
// and returns the value of the 'name' key

Classificação da matriz de objetos

// Lets assume we have class User(name, age) with properties name and age
// and public methods getName() and getAge()
$users = [
    new User('Robert', 20),
    new User('Alex', 30),
    new User('Jack', 25),
];

// Sort list of objects by property value (sort list of users by their name)
$sortedByName = sorted($users, propertyGetter('name'));
$sortedByNameDesc = sorted($users, true, propertyGetter('name'));

// propertyGetter('name') returns a function which takes an object
// and returns the value of its 'name' property

// Sort list of objects by method result (sort list of users by their age)
$sortedByAge = sorted($users, methodCaller('getAge'));
$sortedByAgeDesc = sorted($users, true, methodCaller('getAge'));

// methodCaller('getAge') returns a function which takes an object
// and returns the result of its getAge() method

Classificando com uma função de comparação

// Sort with a comparison function (order words lexicographically with strcmp)
$sortedLexicographically = sorted(['bc', 'a', 'abc'], false, null, 'strcmp');

// Sort with user-defined comparison function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], false, null, function($v1, $v2) {
    return chr($v1[0]) - chr($v2[0]);
});

Você pode ver todos esses exemplos aqui .

Ihor Burlachenko
fonte
2

Se você deseja solicitar pelo valor da chave, pode fazer uma linha, elegante e clara. Isso será ordenado pelo preço crescente. Usa array_multisort e array_column.

   Array([0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => coffee [price] => 9.99 ) [2] => Array ( [name] => rice [price] => 4.04 ) )

   array_multisort (array_column($array, 'price'), SORT_ASC, $array);

para produzir

     Array ( [0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => rice [price] => 4.04 ) [2] => Array ( [name] => coffee [price] => 9.99 ) )
GAV
fonte
1

Esta página é muito abrangente, mas quero acrescentar um pouco mais sobre a incrível utilidade do operador de espaçonave (operador de comparação de três vias) - uma linda criança do PHP7 +.

Usando o operador da nave espacial para implementar várias condições de classificação

Isso faz grandes avanços na redução do inchaço do código e na melhoria da legibilidade.

Ao escrever sua função de classificação personalizada ( usort()/ uasort()/ uksort()) para processar várias condições, você só precisa escrever matrizes balanceadas nos dois lados do operador e retornar o resultado. Não há mais blocos de condição aninhados ou vários retornos.

Os elementos de ambos os lados do operador serão percorridos da esquerda para a direita, um de cada vez, e retornando a avaliação assim que um não empate for encontrado ou quando todos os elementos forem comparados.

Dados de amostra para minhas demonstrações:

$multidimArray = [
    'a' => [
        'boolean' => true,
        'natString' => 'text10',
        'object' => (object)['prop' => 2],
        'float' => -.5,
        'mixed' => []
    ],
    'b' => [
        'boolean' => true,
        'natString' => 'text12',
        'object' => (object)['prop' => 4],
        'float' => 0,
        'mixed' => null
    ],
    'c' => [
        'boolean' => false,
        'natString' => 'text100',
        'object' => (object)['prop' => 9],
        'float' => -.5,
        'mixed' => false
    ],
    'd' => [
        'boolean' => true,
        'natString' => 'text1',
        'object' => (object)['prop' => 9],
        'float' => -5,
        'mixed' => "\0"
    ],
    'e' => [
        'boolean' => false,
        'natString' => 'text2',
        'object' => (object)['prop' => 2],
        'float' => .5,
        'mixed' => ''
    ]
];

Demonstrações (para evitar o inchaço da página Stackoverflow, consulte o link de demonstração das saídas):

  • Lógica de classificação:

    1. DESC booleano (falso = 0, verdadeiro = 1, então é verdadeiro antes de falso)
    2. flutuador ASC

      uasort($multidimArray, function($a, $b) {
          return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']];
      });
  • Lógica de classificação:

    1. ASC misto
    2. objeto ASC
    3. ASC booleano

      uasort($multidimArray, function($a, $b) {
          return [$a['mixed'], $a['object']->prop, $a['boolean']] <=> [$b['mixed'], $b['object']->prop, $b['boolean']];
      });
  • Lógica de classificação:

    1. contagem de propriedades do objeto ASC
    2. iterabilidade do DESC misto
    3. comprimento natString ASC
    4. ASC natString

      uasort($multidimArray, function($a, $b) {
          return [count(get_object_vars($a['object'])), is_iterable($a['mixed']), strlen($a['natString']), $a['natString']]
                 <=>
                 [count(get_object_vars($b['object'])), is_iterable($b['mixed']), strlen($b['natString']), $b['natString']];
      });

Essa sintaxe permite classificar valores, resultados funcionais, dados profundamente aninhados e direção da classificação de maneira elegante. Definitivamente, vale a pena colocar no seu cinto de ferramentas php ... nos casos em que você estiver processando dados que não são do banco de dados - porque é claro que o SQL seria uma técnica muito mais sensata.

A seu critério, a partir do PHP7.4, você pode usar a sintaxe da seta com essas funções anônimas. Mesmo script com sintaxe de seta .

mickmackusa
fonte
0

Se alguém quiser uma solução mais simples para manipular matrizes, basta usar o pacote Laravel Collection, que possui uma função sortBy implementada que permite classificar as chaves de maneira simples.

$collection->sortBy('forename')->sortBy('surname');

ou seja, para classificar primeiro por a, depois b, então c, a cláusula correta seria

sortBy('c')->sortBy('b')->sortBy('a')

https://packagist.org/packages/tightenco/collect

Rizerzero
fonte
-1

Existem várias maneiras de classificar uma matriz. Vou mencionar alguns métodos para executar essa tarefa. Em primeiro lugar, darei uma matriz inteira que é chamada como '$ numbers'.

$number = array(8,9,3,4,0,1,2);

Essa é a maneira normal de criar uma matriz. Suponha que, eu quero classificar essa matriz em ordem crescente.Para isso, o método 'sort ()' pode ser usado.

<?php

    $number = array(8,9,3,4,0,1,2);
    sort($number);

   foreach ($number as $value) {
       echo $value."  ";
   }
?>

Agora considere a saída disso,

insira a descrição da imagem aqui

Você pode ver que a matriz numérica impressa está classificada. Se você deseja que a matriz numérica seja classificada em ordem decrescente, o método 'rsort ()' pode ser usado para essa tarefa.

<?php

     $number = array(8,9,3,4,0,1,2);
     rsort($number);

     foreach ($number as $value) {
        echo $value."  ";
     }
?>

considere a saída ..

insira a descrição da imagem aqui

Agora, a matriz é classificada em ordem decrescente.

$number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);

Então, agora eu quero classificar essa matriz em ordem crescente de acordo com o valor deles. O método 'asort ()' pode ser usado para isso.

<?php

   $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
   asort($number);

   foreach ($number as $value) {
      echo $value."  ";
    }
?>

Se você classificar a ordem decrescente de acordo com seu valor, o método 'arsort ()' poderá ser usado. Suponha que você queira classificar essa matriz de acordo com o valor da chave. Neste, o método 'ksort ()' pode ser usado.

<?php

     $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
     ksort($number);

     foreach ($number as $value) {
         echo $value."  ";
     }
?>

Agora considere a saída. insira a descrição da imagem aqui

Agora a matriz é classificada de acordo com seu valor-chave. Se você deseja classificar a matriz em ordem decrescente de acordo com seu valor-chave, o método 'krsort ()' pode ser usado.

<?php

    $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
    krsort($number);

    foreach ($number as $value) {
       echo $value."  ";
    }
?>

Agora, a matriz associativa é classificada em ordem decrescente de acordo com seu valor-chave. insira a descrição da imagem aqui

Se você está procurando por um array de array em ordem crescente ou decrescente, você pode criar um array em ordem crescente.

GT_hash
fonte
Deceze já não cobre esses insights com: "A diferença entre eles é apenas se as associações de valores-chave são mantidas (as funções" a "), se classifica de baixo para alto ou reverso (" r "), se classifica valores ou chaves ("k") e como ele compara valores ("nat" vs. normal). " na resposta aceita?
Mckmackusa
-2

O mais simples é usar a função usort para classificar a matriz sem nenhum loop: Abaixo está um exemplo:

   $array_compare= array("0" =>4,"1"=>2,"2"=>500,"3"=>100);

Isso será ordenado na ordem desejada:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) > 0 ? 1 :-1;
    });

Isso será ordenado em ordem crescente:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) < 0 ? 1 :-1;
    });
pihu
fonte
1
1) O exemplo e o código são inconsistentes. 2) Isso já é explicado em detalhes excruciantes nas respostas acima. 3) Você está possivelmente tentando responder a uma pergunta diferente?
deceze