Pergunta

Esta questão já tem uma resposta aqui:

I têm dados CSV carregados em uma matriz multidimensional. Deste modo, cada "linha" é uma ficha e cada "coluna" contém o mesmo tipo de dados. Eu estou usando a função a seguir para carregar meu arquivo CSV.

function f_parse_csv($file, $longest, $delimiter)
{
  $mdarray = array();
  $file    = fopen($file, "r");
  while ($line = fgetcsv($file, $longest, $delimiter))
  {
    array_push($mdarray, $line);
  }
  fclose($file);
  return $mdarray;
}

Eu preciso ser capaz de especificar uma coluna para ordenação de modo que reorganiza as linhas. Uma das colunas contém informações de data no formato de Y-m-d H:i:s e eu gostaria de ser capaz de resolver com a data mais recente é a primeira linha.

Foi útil?

Solução

Você pode usar array_multisort ()

Tente algo parecido com isto:

foreach ($mdarray as $key => $row) {
    // replace 0 with the field's index/key
    $dates[$key]  = $row[0];
}

array_multisort($dates, SORT_DESC, $mdarray);

Para PHP> = 5.5.0 apenas extrair a coluna para ordenar por. Não há necessidade do loop:

array_multisort(array_column($mdarray, 0), SORT_DESC, $mdarray);

Outras dicas

Apresentando: uma solução muito generalizada para PHP 5.3 +

I 'd como para adicionar a minha própria solução aqui, uma vez que oferece recursos que outras respostas não.

Especificamente, vantagens desta solução incluem:

  1. do reutilizável :. Especificar a coluna de classificação como uma variável em vez de codificá-lo
  2. do flexível :. Você pode especificar várias colunas de ordenação (quantos você quiser) - colunas adicionais são usados ??como critério de desempate entre os itens que inicialmente comparar igual
  3. do reversível :. Você pode especificar que o tipo deve ser revertida - individualmente para cada coluna
  4. do extensível : se o conjunto de dados contém colunas que não podem ser comparados de forma "burro" (por exemplo, textos de data), você também pode especificar como converter esses itens para um valor que pode ser diretamente comparação (por exemplo, um DateTime exemplo).
  5. do associativa se você quiser :. Este código cuida de itens de classificação, mas você , selecione a função de classificação real (usort ou uasort)
  6. Finalmente, ele não usa array_multisort: enquanto array_multisort é conveniente, ele depende da criação de uma projeção de todos os seus dados de entrada antes da separação. Isso consome tempo e memória e pode ser simplesmente proibitivo se o seu conjunto de dados é grande.

O código

function make_comparer() {
    // Normalize criteria up front so that the comparer finds everything tidy
    $criteria = func_get_args();
    foreach ($criteria as $index => $criterion) {
        $criteria[$index] = is_array($criterion)
            ? array_pad($criterion, 3, null)
            : array($criterion, SORT_ASC, null);
    }

    return function($first, $second) use (&$criteria) {
        foreach ($criteria as $criterion) {
            // How will we compare this round?
            list($column, $sortOrder, $projection) = $criterion;
            $sortOrder = $sortOrder === SORT_DESC ? -1 : 1;

            // If a projection was defined project the values now
            if ($projection) {
                $lhs = call_user_func($projection, $first[$column]);
                $rhs = call_user_func($projection, $second[$column]);
            }
            else {
                $lhs = $first[$column];
                $rhs = $second[$column];
            }

            // Do the actual comparison; do not return if equal
            if ($lhs < $rhs) {
                return -1 * $sortOrder;
            }
            else if ($lhs > $rhs) {
                return 1 * $sortOrder;
            }
        }

        return 0; // tiebreakers exhausted, so $first == $second
    };
}

Como usar

Ao longo desta secção I irá fornecer links desse tipo este conjunto de dados de amostra:

$data = array(
    array('zz', 'name' => 'Jack', 'number' => 22, 'birthday' => '12/03/1980'),
    array('xx', 'name' => 'Adam', 'number' => 16, 'birthday' => '01/12/1979'),
    array('aa', 'name' => 'Paul', 'number' => 16, 'birthday' => '03/11/1987'),
    array('cc', 'name' => 'Helen', 'number' => 44, 'birthday' => '24/06/1967'),
);

O básico

A função make_comparer aceita um número variável de argumentos que definem o desejado tipo e retorna uma função que você é suposto a utilização como o argumento para usort ou uasort.

O caso de uso mais simples é passar na chave que você 'd gostam de usar para comparar itens de dados. Por exemplo, para classificar $data pelo item name você faria

usort($data, make_comparer('name'));

vê-lo em ação .

A chave também pode ser um número, se os itens são numericamente matrizes indexadas. Para o exemplo em questão, isso seria

usort($data, make_comparer(0)); // 0 = first numerically indexed column

vê-lo em ação .

Várias colunas de ordenação

Você pode especificar várias colunas de ordenação passando parâmetros adicionais para make_comparer. Por exemplo, para classificar por "número" e depois pela coluna zero indexada:

usort($data, make_comparer('number', 0));

vê-lo em ação .

Funções avançadas

Mais recursos avançados estão disponíveis se você especificar uma coluna de classificação como uma matriz em vez de uma seqüência simples. Esta matriz deve ser numericamente indexado, e deve conter os seguintes itens:

0 => the column name to sort on (mandatory)
1 => either SORT_ASC or SORT_DESC (optional)
2 => a projection function (optional)

Vamos ver como podemos usar esses recursos.

reversa tipo

Para classificar por nome descendente:

usort($data, make_comparer(['name', SORT_DESC]));

vê-lo em ação .

Para ordenar por número descendente e, em seguida, pelo nome descendente:

usort($data, make_comparer(['number', SORT_DESC], ['name', SORT_DESC]));

vê-lo em ação .

projeções feitos sob encomenda

Em alguns cenários pode ser necessário ordenar por uma coluna cujos valores não se prestam bem para a classificação. A coluna "aniversário" no conjunto de dados de amostra se encaixa nessa descrição: não faz sentido comparar aniversários como strings (porque, por exemplo "01/01/1980" vem antes de "1970/10/10"). Neste caso queremos especificar como projecto os dados reais para uma forma que pode ser comparada diretamente com a semântica desejados.

As projeções pode ser especificado como qualquer tipo de exigível : como strings, matrizes, ou anônimos funções. Uma projecção é assumido para aceitar um argumento e rELigue sua forma projetada.

Deve-se notar que, enquanto as projeções são semelhantes às funções de comparação personalizados usados ??com usort e família, eles são mais simples (você só precisa converter um valor para outro) e tirar proveito de todas as funcionalidades já cozido em make_comparer.

Classificar os dados de exemplo de deixar o jogo sem uma projeção e ver o que acontece:

usort($data, make_comparer('birthday'));

vê-lo em ação .

Isso não era o resultado desejado. Mas podemos usar date_create como uma projeção:

usort($data, make_comparer(['birthday', SORT_ASC, 'date_create']));

vê-lo em ação .

Esta é a ordem correta que queríamos.

Existem muitas outras coisas que as projeções podem alcançar. Por exemplo, uma maneira rápida de obter uma espécie de maiúsculas e minúsculas é usar strtolower como uma projeção.

Dito isso, eu também deve mencionar que é melhor não usar projeções se o seu conjunto de dados é grande: nesse caso seria muito mais rápido para projetar todos os seus dados manualmente na frente e, em seguida, tipo sem o uso de uma projeção, embora fazendo por isso vai trocar o uso de memória aumentado para mais rápido tipo de velocidade.

Finalmente, aqui está um exemplo que usa todas as características: primeiro ele classifica por número descendente, em seguida, por ascendente aniversário:

usort($data, make_comparer(
    ['number', SORT_DESC],
    ['birthday', SORT_ASC, 'date_create']
));

vê-lo em ação .

Com usort . Aqui está uma solução genérica, que você pode usar para diferentes colunas:

class TableSorter {
  protected $column;
  function __construct($column) {
    $this->column = $column;
  }
  function sort($table) {
    usort($table, array($this, 'compare'));
    return $table;
  }
  function compare($a, $b) {
    if ($a[$this->column] == $b[$this->column]) {
      return 0;
    }
    return ($a[$this->column] < $b[$this->column]) ? -1 : 1;
  }
}

Para ordenar por primeira coluna:

$sorter = new TableSorter(0); // sort by first column
$mdarray = $sorter->sort($mdarray);

linha múltipla classificação usando um fechamento

Aqui está outra uasort abordagem usando () e uma função de retorno de chamada anónima (fechamento). Eu usei essa função regularmente. PHP 5.3 necessário - não mais dependências

/**
 * Sorting array of associative arrays - multiple row sorting using a closure.
 * See also: http://the-art-of-web.com/php/sortarray/
 *
 * @param array $data input-array
 * @param string|array $fields array-keys
 * @license Public Domain
 * @return array
 */
function sortArray( $data, $field ) {
    $field = (array) $field;
    uasort( $data, function($a, $b) use($field) {
        $retval = 0;
        foreach( $field as $fieldname ) {
            if( $retval == 0 ) $retval = strnatcmp( $a[$fieldname], $b[$fieldname] );
        }
        return $retval;
    } );
    return $data;
}

/* example */
$data = array(
    array( "firstname" => "Mary", "lastname" => "Johnson", "age" => 25 ),
    array( "firstname" => "Amanda", "lastname" => "Miller", "age" => 18 ),
    array( "firstname" => "James", "lastname" => "Brown", "age" => 31 ),
    array( "firstname" => "Patricia", "lastname" => "Williams", "age" => 7 ),
    array( "firstname" => "Michael", "lastname" => "Davis", "age" => 43 ),
    array( "firstname" => "Sarah", "lastname" => "Miller", "age" => 24 ),
    array( "firstname" => "Patrick", "lastname" => "Miller", "age" => 27 )
);

$data = sortArray( $data, 'age' );
$data = sortArray( $data, array( 'lastname', 'firstname' ) );

Eu sei que é de 2 anos desde que esta pergunta foi feita e respondida, mas aqui está uma outra função que classifica uma matriz bidimensional. Ele aceita um número variável de argumentos, o que lhe permite passar em mais de uma chave (ou seja, nome da coluna) para classificar por. PHP 5.3 necessário.

function sort_multi_array ($array, $key)
{
  $keys = array();
  for ($i=1;$i<func_num_args();$i++) {
    $keys[$i-1] = func_get_arg($i);
  }

  // create a custom search function to pass to usort
  $func = function ($a, $b) use ($keys) {
    for ($i=0;$i<count($keys);$i++) {
      if ($a[$keys[$i]] != $b[$keys[$i]]) {
        return ($a[$keys[$i]] < $b[$keys[$i]]) ? -1 : 1;
      }
    }
    return 0;
  };

  usort($array, $func);

  return $array;
}

Experimente-o aqui: http://www.exorithm.com/algorithm/view/sort_multi_array

function cmp($a, $b)
{
$p1 = $a['price'];
$p2 = $b['price'];
return (float)$p1 > (float)$p2;
}
uasort($my_array, "cmp");

http://qaify.com/sort-an-array-of-associative-arrays-by-value-of-given-key-in-php/

A função "usort" é sua resposta.
http://php.net/usort

Aqui está uma classe php4 / php5 que irá classificar um ou mais campos:

// a sorter class
//  php4 and php5 compatible
class Sorter {

  var $sort_fields;
  var $backwards = false;
  var $numeric = false;

  function sort() {
    $args = func_get_args();
    $array = $args[0];
    if (!$array) return array();
    $this->sort_fields = array_slice($args, 1);
    if (!$this->sort_fields) return $array();

    if ($this->numeric) {
      usort($array, array($this, 'numericCompare'));
    } else {
      usort($array, array($this, 'stringCompare'));
    }
    return $array;
  }

  function numericCompare($a, $b) {
    foreach($this->sort_fields as $sort_field) {
      if ($a[$sort_field] == $b[$sort_field]) {
        continue;
      }
      return ($a[$sort_field] < $b[$sort_field]) ? ($this->backwards ? 1 : -1) : ($this->backwards ? -1 : 1);
    }
    return 0;
  }

  function stringCompare($a, $b) {
    foreach($this->sort_fields as $sort_field) {
      $cmp_result = strcasecmp($a[$sort_field], $b[$sort_field]);
      if ($cmp_result == 0) continue;

      return ($this->backwards ? -$cmp_result : $cmp_result);
    }
    return 0;
  }
}

/////////////////////
// usage examples

// some starting data
$start_data = array(
  array('first_name' => 'John', 'last_name' => 'Smith', 'age' => 10),
  array('first_name' => 'Joe', 'last_name' => 'Smith', 'age' => 11),
  array('first_name' => 'Jake', 'last_name' => 'Xample', 'age' => 9),
);

// sort by last_name, then first_name
$sorter = new Sorter();
print_r($sorter->sort($start_data, 'last_name', 'first_name'));

// sort by first_name, then last_name
$sorter = new Sorter();
print_r($sorter->sort($start_data, 'first_name', 'last_name'));

// sort by last_name, then first_name (backwards)
$sorter = new Sorter();
$sorter->backwards = true;
print_r($sorter->sort($start_data, 'last_name', 'first_name'));

// sort numerically by age
$sorter = new Sorter();
$sorter->numeric = true;
print_r($sorter->sort($start_data, 'age'));

Antes que eu pudesse obter a classe TableSorter para executar eu tinha veio com uma função com base no que Shinhan tinha fornecido.

function sort2d_bycolumn($array, $column, $method, $has_header)
  {
  if ($has_header)  $header = array_shift($array);
  foreach ($array as $key => $row) {
    $narray[$key]  = $row[$column]; 
    }
  array_multisort($narray, $method, $array);
  if ($has_header) array_unshift($array, $header);
  return $array;
  }
  • $ array é a matriz MD que você deseja classificar.
  • $ coluna é a coluna que deseja ordenar por.
  • $ método é como você quer o tipo executada, como SORT_DESC
  • $ has_header é definido como verdadeiro se a primeira linha contém valores de cabeçalho que você não quer ordenados.

Eu tentei vários array_multisort popular () e usort () respostas e nenhum deles funcionou para mim. Os dados só fica desordenados eo código é ilegível. Aqui está uma solução suja rápido. ATENÇÃO: Só use isso se você tiver certeza de um delimitador desonestos não vai voltar para assombrá-lo mais tarde!

Digamos que cada linha em seus múltiplos olhares matriz como: nome, stuff1, stuff2:

// Sort by name, pull the other stuff along for the ride
foreach ($names_stuff as $name_stuff) {
    // To sort by stuff1, that would be first in the contatenation
    $sorted_names[] = $name_stuff[0] .','. name_stuff[1] .','. $name_stuff[2];
}
sort($sorted_names, SORT_STRING);

Precisa de costas coisas em ordem alfabética?

foreach ($sorted_names as $sorted_name) {
    $name_stuff = explode(',',$sorted_name);
    // use your $name_stuff[0] 
    // use your $name_stuff[1] 
    // ... 
}

Sim, é sujo. Mas super fácil, não vai fazer sua cabeça explodir.

Eu prefiro usar array_multisort. Consulte a documentação aqui .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top