Domanda

Questa domanda ha già una risposta qui:

Ho caricato i dati CSV in un array multidimensionale.In questo modo ogni "riga" è un record e ogni "colonna" contiene lo stesso tipo di dati.Sto utilizzando la funzione seguente per caricare il mio file 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;
}

Devo essere in grado di specificare una colonna da ordinare in modo da riorganizzare le righe.Una delle colonne contiene informazioni sulla data nel formato di Y-m-d H:i:s e vorrei poter ordinare con la data più recente nella prima riga.

È stato utile?

Soluzione

Puoi usare array_multisort()

Prova qualcosa del genere:

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

array_multisort($dates, SORT_DESC, $mdarray);

Per PHP >= 5.5.0 basta estrarre la colonna in base alla quale ordinare.Non è necessario il ciclo:

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

Altri suggerimenti

Presentazione:una soluzione molto generalizzata per PHP 5.3+

Vorrei aggiungere qui la mia soluzione, poiché offre funzionalità che altre risposte non offrono.

Nello specifico i vantaggi di questa soluzione includono:

  1. Suo riutilizzabile:specifichi la colonna di ordinamento come variabile invece di codificarla.
  2. Suo flessibile:puoi specificare più colonne di ordinamento (quante ne vuoi): le colonne aggiuntive vengono utilizzate come separatori tra gli elementi che inizialmente risultano uguali.
  3. Suo reversibile:puoi specificare che l'ordinamento deve essere invertito, individualmente per ciascuna colonna.
  4. Suo estensibile:se il set di dati contiene colonne che non possono essere confrontate in modo "stupido" (ad es.stringhe di data) puoi anche specificare come convertire questi elementi in un valore che possa essere direttamente confrontato (es.UN DateTime esempio).
  5. Suo associativo se vuoi:questo codice si occupa dell'ordinamento degli elementi, ma Voi selezionare la funzione di ordinamento effettiva (usort O uasort).
  6. Infine, non utilizza array_multisort:Mentre array_multisort è conveniente, dipende dalla creazione di una proiezione di tutti i dati di input prima dell'ordinamento.Ciò consuma tempo e memoria e potrebbe essere semplicemente proibitivo se il set di dati è di grandi dimensioni.

Il codice

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
    };
}

Come usare

In questa sezione fornirò i collegamenti che ordinano questo set di dati di esempio:

$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'),
);

Le basi

La funzione make_comparer accetta un numero variabile di argomenti che definiscono l'ordinamento desiderato e restituisce una funzione che dovresti utilizzare come argomento usort O uasort.

Il caso d'uso più semplice è passare la chiave che desideri utilizzare per confrontare gli elementi di dati.Ad esempio, per ordinare $data dal name oggetto che faresti

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

Guardalo in azione.

La chiave può anche essere un numero se gli elementi sono matrici indicizzate numericamente.Per l'esempio nella domanda, questo sarebbe

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

Guardalo in azione.

Colonne di ordinamento multiple

È possibile specificare più colonne di ordinamento passando parametri aggiuntivi a make_comparer.Ad esempio, per ordinare in base al "numero" e quindi alla colonna con indice zero:

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

Guardalo in azione.

Funzionalità avanzate

Sono disponibili funzionalità più avanzate se si specifica una colonna di ordinamento come array anziché come semplice stringa.Questo array deve essere indicizzato numericamente e deve contenere questi elementi:

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

Vediamo come possiamo utilizzare queste funzionalità.

Ordinamento inverso

Per ordinare per nome discendente:

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

Guardalo in azione.

Per ordinare per numero discendente e poi per nome discendente:

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

Guardalo in azione.

Proiezioni personalizzate

In alcuni scenari potrebbe essere necessario ordinare in base a una colonna i cui valori non si prestano bene all'ordinamento.La colonna "compleanno" nel set di dati di esempio corrisponde a questa descrizione:non ha senso confrontare i compleanni come stringhe (perché ad es."01/01/1980" viene prima di "10/10/1970").In questo caso vogliamo specificare come fare progetto i dati effettivi in ​​un modulo che Potere essere confrontato direttamente con la semantica desiderata.

Le proiezioni possono essere specificate come qualsiasi tipo di richiamabile:come stringhe, array o funzioni anonime.Si presuppone che una proiezione accetti un argomento e restituisca la sua forma proiettata.

Va notato che mentre le proiezioni sono simili alle funzioni di confronto personalizzate utilizzate con usort e famiglia, sono più semplici (è sufficiente convertire un valore in un altro) e sfruttano tutte le funzionalità già integrate make_comparer.

Ordiniamo il set di dati di esempio senza proiezione e vediamo cosa succede:

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

Guardalo in azione.

Questo non era il risultato desiderato.Ma possiamo usare date_create come proiezione:

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

Guardalo in azione.

Questo è l'ordine corretto che volevamo.

Ci sono molte altre cose che le proiezioni possono ottenere.Ad esempio, un modo rapido per ottenere un ordinamento senza distinzione tra maiuscole e minuscole è utilizzare strtolower come proiezione.

Detto questo, dovrei anche menzionare che è meglio non utilizzare le proiezioni se il set di dati è di grandi dimensioni:in tal caso sarebbe molto più veloce proiettare manualmente tutti i dati in anticipo e quindi ordinarli senza utilizzare una proiezione, anche se così facendo si scambierebbe un maggiore utilizzo della memoria con una maggiore velocità di ordinamento.

Infine, ecco un esempio che utilizza tutte le funzionalità:prima ordina per numero discendente, poi per compleanno ascendente:

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

Guardalo in azione.

Con usort.Ecco una soluzione generica, che puoi utilizzare per diverse colonne:

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;
  }
}

Per ordinare in base alla prima colonna:

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

Ordinamento di più righe utilizzando una chiusura

Ecco un altro approccio che utilizza uasort() e una funzione di callback anonima (chiusura).Ho usato quella funzione regolarmente. È richiesto PHP 5.3 – niente più dipendenze!

/**
 * 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' ) );

So che sono passati 2 anni da quando è stata posta e data risposta a questa domanda, ma ecco un'altra funzione che ordina un array bidimensionale.Accetta un numero variabile di argomenti, consentendoti di passare più di una chiave (ad esempio il nome della colonna) in base a cui ordinare.È richiesto PHP 5.3.

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;
}

Provalo qui: 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/

La funzione "Usort" è la tua risposta.
http://php.net/usort

Ecco una classe php4/php5 che ordinerà uno o più campi:

// 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'));

Prima di poter eseguire la classe TableSorter, avevo ideato una funzione basata su what Shinhan aveva fornito.

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 è l'array MD che desideri ordinare.
  • $colonna è la colonna in base alla quale desideri ordinare.
  • $method è il modo in cui desideri che venga eseguito l'ordinamento, ad esempio SORT_DESC
  • $has_header è impostato su true se la prima riga contiene valori di intestazione che non desideri ordinare.

Ho provato diverse risposte popolari array_multisort() e usort() e nessuna ha funzionato per me.I dati vengono semplicemente confusi e il codice è illeggibile.Ecco una soluzione rapida e sporca.AVVERTIMENTO:Usalo solo se sei sicuro che un delimitatore canaglia non tornerà a perseguitarti più tardi!

Diciamo che ogni riga nel tuo multi array assomiglia a:nome, roba1, roba2:

// 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);

Hai bisogno di riportare le tue cose in ordine alfabetico?

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

Sì, è sporco.Ma super facile, non ti farà esplodere la testa.

Preferisco usare array_multisort.Consulta la documentazioneQui.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top