PHP Classifica um array multidimensional por elemento contendo data

113

Eu tenho uma matriz como:

Array
(
[0] => Array
    (
        [id] => 2
        [type] => comment
        [text] => hey
        [datetime] => 2010-05-15 11:29:45
    )

[1] => Array
    (
        [id] => 3
        [type] => status
        [text] => oi
        [datetime] => 2010-05-26 15:59:53
    )

[2] => Array
    (
        [id] => 4
        [type] => status
        [text] => yeww
        [datetime] => 2010-05-26 16:04:24
    )

)

Alguém pode sugerir uma maneira de classificar / ordenar isso com base no elemento datetime?

Tim
fonte

Respostas:

205

Use usort()e uma função de comparação personalizada:

function date_compare($a, $b)
{
    $t1 = strtotime($a['datetime']);
    $t2 = strtotime($b['datetime']);
    return $t1 - $t2;
}    
usort($array, 'date_compare');

EDIT : Seus dados são organizados em uma variedade de matrizes. Para melhor distingui-los, vamos chamar os registros de matrizes internas (dados), de modo que seus dados realmente sejam uma matriz de registros.

usortirá passar dois desses registros para a função de comparação fornecida date_compare()ao mesmo tempo. date_compareentão extrai o "datetime"campo de cada registro como um carimbo de data / hora UNIX (um inteiro) e retorna a diferença, de modo que o resultado será 0se as duas datas forem iguais, um número positivo se o primeiro ( $a) for maior ou um valor negativo se o o segundo argumento ( $b) é maior. usort()usa essas informações para classificar a matriz.

Ferdinand Beyer
fonte
1
neste exemplo, $ array precisa conter os elementos $ a e $ b? - estou recebendo um erro de função de comparação inválida
Tim
Não, $ae $bmanterá as matrizes dentro $array. Certifique-se de que você não digitou incorretamente o nome da função.
Ferdinand Beyer
eu não tenho certeza se entendi. No meu exemplo, tenho 3 matrizes na matriz - confirmei o nome, ainda obtendo função de comparação inválida
Tim
Veja a explicação que adicionei. Testei o código e funciona bem para mim!
Ferdinand Beyer
9
Não sei CodeIgniter, mas você está definindo a função dentro de uma classe? Então, você deve defini-lo fora da classe ou usar um argumento de retorno de chamada diferente:, usort($array, array($this, "date_compare"))para que usort()saiba que é uma função / método de classe. Veja também: php.net/manual/en/…
Ferdinand Beyer
45

Isso deve funcionar. Eu converti a data para hora unix via strtotime.

  foreach ($originalArray as $key => $part) {
       $sort[$key] = strtotime($part['datetime']);
  }
  array_multisort($sort, SORT_DESC, $originalArray);

A versão de uma linha usaria vários métodos de array:

array_multisort(array_map('strtotime',array_column($originalArray,'datetime')),
                SORT_DESC, 
                $originalArray);
Dave None
fonte
Isso funciona muito bem. Basta substituir: $ originalArray pelo nome do seu array multidimensional. E substitua: 'datetime' pelo nome do seu campo de submatriz para data. Obrigado.
esteve aqui
1
esta solução está indo bem para mim. a opção de classificação também é ótima (SORT_ASC ou SORT_DESC). Muito obrigado.
Andras Barth
funciona perfeitamente com uma pequena advertência (ou isso, ou estou fazendo algo errado) ... o campo de data pelo qual preciso classificar tem datas no formato dd / mm / aaaa ou aaaa / mm / dd (com barras). Nesse caso, a classificação não funcionou por algum motivo (classificado apenas pelo dia, não pela data inteira). Eu pré-processei as datas para convertê-las em dd-mm-aaaa ou aaaa-mm-dd e funcionou, então obrigado !!! (alguma ideia de por que funciona com hífens, mas não barras?)
Javier Larroulet
array_multisort é o único método de classificação que funcionou para classificar meu arquivo json por pubdate. obrigado.
grc
Funcionando muito bem para mim, obrigado
Fernando Torres
41

No php7, você pode usar o operador Spaceship :

usort($array, function($a, $b) {
  return new DateTime($a['datetime']) <=> new DateTime($b['datetime']);
});
Federkun
fonte
6

http://us2.php.net/manual/en/function.array-multisort.php veja o terceiro exemplo:

<?php

$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);

foreach ($data as $key => $row) {
    $volume[$key]  = $row['volume'];
    $edition[$key] = $row['edition'];
}

array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data);

?>

fyi, usar um unix (segundos de 1970) ou um timestamp mysql (YmdHis - 20100526014500) seria mais fácil para o analisador, mas acho que no seu caso não faz diferença.

Toby
fonte
5

Classificando a matriz de registros / assoc_arrays por campo de data e hora mysql especificado e por ordem:

function build_sorter($key, $dir='ASC') {
    return function ($a, $b) use ($key, $dir) {
        $t1 = strtotime(is_array($a) ? $a[$key] : $a->$key);
        $t2 = strtotime(is_array($b) ? $b[$key] : $b->$key);
        if ($t1 == $t2) return 0;
        return (strtoupper($dir) == 'ASC' ? ($t1 < $t2) : ($t1 > $t2)) ? -1 : 1;
    };
}


// $sort - key or property name 
// $dir - ASC/DESC sort order or empty
usort($arr, build_sorter($sort, $dir));
falko
fonte
Totalmente o que preciso. Mas deve mudar str_to_upperpara strtoupper.
Jimmy Adaro
4

$array = Array
(
  [0] => Array
   (
    [id] => 2
    [type] => comment
    [text] => hey
    [datetime] => 2010-05-15 11:29:45
   )

 [1] => Array
  (
    [id] => 3
    [type] => status
    [text] => oi
    [datetime] => 2010-05-26 15:59:53
  )

  [2] => Array
   (
    [id] => 4
    [type] => status
    [text] => yeww
    [datetime] => 2010-05-26 16:04:24
   )

   );
   print_r($array);   
   $name = 'datetime';
   usort($array, function ($a, $b) use(&$name){
      return $a[$name] - $b[$name];});

   print_r($array);
Ajit Kumar
fonte
4

Você pode simplesmente resolver este problema usando usort () com função de retorno de chamada. Não há necessidade de escrever nenhuma função personalizada.

$your_date_field_name = 'datetime';
usort($your_given_array_name, function ($a, $b) use (&$your_date_field_name) {
    return strtotime($a[$your_date_field_name]) - strtotime($b[$your_date_field_name]);
});
Faisal
fonte
1

Eu me deparei com esta postagem, mas queria classificar por tempo ao devolver os itens dentro da minha classe e recebi um erro.

Então, pesquiso o site php.net e acabo fazendo o seguinte:

class MyClass {
   public function getItems(){
      usort( $this->items, array("MyClass", "sortByTime") );
      return $this->items;
   }
   public function sortByTime($a, $b){
      return $b["time"] - $a["time"];
   }
}

Você pode encontrar exemplos muito úteis no site PHP.net

Meu array era assim:

  'recent' => 
    array
      92 => 
        array
          'id' => string '92' (length=2)
          'quantity' => string '1' (length=1)
          'time' => string '1396514041' (length=10)
      52 => 
        array
          'id' => string '52' (length=2)
          'quantity' => string '8' (length=1)
          'time' => string '1396514838' (length=10)
      22 => 
        array
          'id' => string '22' (length=2)
          'quantity' => string '1' (length=1)
          'time' => string '1396514871' (length=10)
      81 => 
        array
          'id' => string '81' (length=2)
          'quantity' => string '2' (length=1)
          'time' => string '1396514988' (length=10)
Tijolo Imutável
fonte
1

Para 'd/m/Y'datas:

usort($array, function ($a, $b, $i = 'datetime') { 
    $t1 = strtotime(str_replace('/', '-', $a[$i]));
    $t2 = strtotime(str_replace('/', '-', $b[$i]));

    return $t1 > $t2;
});

onde $iestá o índice da matriz

Borjovsky
fonte
1

Para aqueles que ainda procuram um resolvido desta forma dentro de uma classe com uma função sortByDate, veja o código abaixo

<?php

class ContactsController 
{
    public function __construct()
    {
    //
    }


    function sortByDate($key)
    {
        return function ($a, $b) use ($key) {
            $t1 = strtotime($a[$key]);
            $t2 = strtotime($b[$key]);
            return $t2-$t1;
        };

    }

    public function index()
    {

        $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-11 12:38:23','created_at' =>'2020-06-11 12:38:23');
        $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-16 12:38:23','created_at' =>'2020-06-10 12:38:23');
        $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-7 12:38:23','created_at' =>'2020-06-9 12:38:23');


        usort($data, $this->sortByDate('updated_at'));

        //usort($data, $this->sortByDate('created_at'));
        echo $data;

    }
}
Dickson Godwin
fonte