Jak posortować tablicę wielowymiarową w PHP [duplikat]

To pytanie ma już odpowiedź tutaj:

Mam dane CSV załadowane do wielowymiarowej tablicy. W ten sposób każdy " wiersz "jest rekordem, a każda" kolumna " zawiera ten sam typ danych. Używam poniższej funkcji, aby załadować mój plik 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;
}

Muszę być w stanie określić kolumna do sortowania tak, aby przestawiała wiersze. Jedna z kolumn zawiera informacje o dacie w formacie Y-m-d H:i:s I chciałbym móc sortować z ostatnią datą będącą pierwszym wierszem.

Author: hakre, 2008-09-19

11 answers

Możesz użyć array_multisort()

Spróbuj czegoś takiego:

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

array_multisort($dates, SORT_DESC, $mdarray);

Dla PHP > = 5.5.0 po prostu wyodrębnij kolumnę, aby ją posortować. Nie potrzeba pętli:

array_multisort(array_column($mdarray, 0), SORT_DESC, $mdarray);
 202
Author: Shinhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-08 17:18:23

Przedstawiamy: bardzo uogólnione rozwiązanie dla PHP 5.3 +

Chciałbym dodać własne rozwiązanie tutaj, ponieważ oferuje funkcje, które Inne odpowiedzi nie.

W szczególności zalety tego rozwiązania to:

  1. jest to wielokrotnego użytku: kolumnę sortowania określa się jako zmienną zamiast jej kodowania na twardo.
  2. it ' s flexible : możesz określić wiele kolumn sortowania (tyle ile chcesz) -- dodatkowe kolumny są używane jako tiebreakers pomiędzy elementy, które początkowo są równe.
  3. to odwracalne : możesz określić, że sortowanie powinno być odwrócone -- indywidualnie dla każdej kolumny.
  4. it 's extensible : jeśli zestaw danych zawiera kolumny, których nie można porównać w "głupi" sposób (np. ciągi daty), Możesz również określić, jak przekonwertować te elementy na wartość, która może być bezpośrednio porównana(np. instancja DateTime).
  5. jest asocjacyjny jeśli chcesz : ten kod zajmuje się sortowaniem pozycji, ale ty wybierz rzeczywistą funkcję sortowania (usort lub uasort).
  6. wreszcie, nie używa array_multisort: chociaż array_multisort jest wygodne, to zależy od utworzenia projekcji wszystkich danych wejściowych przed sortowaniem. To pochłania czas i pamięć i może być po prostu wygórowane, jeśli zestaw danych jest duży.

Kod

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

Jak używać

W tym dziale podam linki, które sortują ten przykładowy zestaw danych:

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

The podstawy

Funkcja make_comparer akceptuje zmienną liczbę argumentów, które definiują pożądany sortowanie i zwraca funkcję, której powinieneś użyć jako argumentu do usort lub uasort.

Najprostszym przypadkiem użycia jest przekazanie klucza, którego chcesz użyć do porównania pozycji danych. Na przykład, aby posortować $data według pozycji name, wykonasz

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

Zobacz to w akcji.

Kluczem może być również Liczba, jeśli elementy są indeksowane numerycznie tablice. Dla przykładu w pytaniu byłoby to

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

Zobacz to w akcji.

Wiele kolumn sortowania

Możesz określić wiele kolumn sortowania, przekazując dodatkowe parametry do make_comparer. Na przykład, aby sortować według "liczby", a następnie według kolumny indeksowanej zero:

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

Zobacz to w akcji.

Zaawansowane funkcje

Bardziej zaawansowane funkcje są dostępne, jeśli zamiast tego określisz kolumnę sortowania jako tablicę prostego Sznurka. Tablica ta powinna być indeksowana numerycznie i musi zawierać następujące elementy:

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

Zobaczmy, jak możemy wykorzystać te funkcje.

Sortowanie odwrotne

Aby sortować po nazwie malejąco:

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

Zobacz to w akcji.

Aby sortować po liczbie malejąco, a następnie po nazwie malejąco:

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

Zobacz to w akcji.

Projekcje niestandardowe

W niektórych scenariuszach może być konieczne sortowanie według kolumna, której wartości nie nadają się dobrze do sortowania. Kolumna "urodziny" w zestawie danych przykładowych pasuje do tego opisu: nie ma sensu porównywać urodzin jako ciągi znaków (ponieważ np. "01/01/1980" jest przed "10/10/1970"). W tym przypadku chcemy określić, jak projekt rzeczywiste dane do postaci, która może być porównywana bezpośrednio z pożądaną semantyką.

Projekcje mogą być określone jako dowolny typ wywoływalny : jako ciągi znaków, tablice lub anonimowe funkcje. Zakłada się, że rzut przyjmuje jeden argument i zwraca jego rzutowaną postać.

Należy zauważyć, że chociaż projekcje są podobne do niestandardowych funkcji porównawczych używanych z usort i rodziną, są prostsze (wystarczy zamienić jedną wartość na drugą) i wykorzystać wszystkie funkcjonalności już upieczone do make_comparer.

Posortujmy przykładowy zbiór danych bez projekcji i zobaczmy, co się stanie:

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

Zobacz to w działanie.

To nie był pożądany rezultat. Ale możemy użyć date_create jako rzut:

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

Zobacz to w akcji.

To jest prawidłowa kolejność, którą chcieliśmy.

Jest o wiele więcej rzeczy, które projekcje mogą osiągnąć. Na przykład, szybkim sposobem uzyskania sortowania bez rozróżniania wielkości liter jest użycie strtolower jako projekcji.

To powiedziawszy, powinienem również wspomnieć, że lepiej nie używać prognoz, jeśli zestaw danych jest duży: w takim przypadku byłoby znacznie szybciej ręcznie wyświetlać wszystkie dane z przodu, a następnie sortować bez użycia projekcji, chociaż spowoduje to zwiększenie zużycia pamięci na szybsze sortowanie.

Na koniec, oto przykład, który używa wszystkich funkcji: najpierw sortuje według liczby malejącej, a następnie rosnącej według daty urodzin:

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

Zobacz to w akcji.

 332
Author: Jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-28 14:34:33

Z usort . Oto ogólne rozwiązanie, które możesz użyć dla różnych kolumn:

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

Do sortowania według pierwszej kolumny:

$sorter = new TableSorter(0); // sort by first column
$mdarray = $sorter->sort($mdarray);
 31
Author: troelskn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:53:11

Sortowanie wielu wierszy za pomocą zamknięcia

Oto inne podejście wykorzystujące uasort () i anonimową funkcję zwrotną (closure). Korzystałem z tej funkcji regularnie. wymagane PHP 5.3 - koniec z zależnościami!

/**
 * 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' ) );
 10
Author: feeela,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-13 14:38:54

Wiem, że minęły 2 lata odkąd to pytanie zostało zadane i odpowiedziane, ale oto kolejna funkcja, która sortuje tablicę dwuwymiarową. Akceptuje zmienną liczbę argumentów, pozwalając na przekazanie więcej niż jednego klucza (np. nazwa kolumny) do sortowania według. Wymagane 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;
}

Spróbuj tutaj: http://www.exorithm.com/algorithm/view/sort_multi_array

 6
Author: Mike C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-19 23:21:51
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/

 6
Author: Kamal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-24 07:51:05

Funkcja "Usort" jest twoją odpowiedzią.
http://php.net/usort

 3
Author: Jan Hančič,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-13 18:43:22

Oto Klasa php4 / php5, która posortuje jedno lub więcej pól:

// 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'));
 2
Author: Devon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 22:16:00

Zanim udało mi się uruchomić klasę TableSorter, wymyśliłem funkcję opartą na tym, co dostarczył Shinhan.

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 jest tablicą MD, którą chcesz posortować.
  • $column jest kolumną, którą chcesz sortować według.
  • $ metoda jest jak chcesz sortowania wykonywane, np SORT_DESC
  • $has_header jest ustawione na true, jeśli pierwszy wiersz zawiera wartości nagłówka, których nie chcesz sortować.
 0
Author: Melikoth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:04

Próbowałem kilku popularnych odpowiedzi array_multisort () i usort() i żadna z nich nie zadziałała dla mnie. Dane są pomieszane, a kod jest nieczytelny. Oto szybkie brudne rozwiązanie. Ostrzeżenie: używaj tego tylko wtedy, gdy jesteś pewien, że nieuczciwy ogranicznik nie wróci, aby cię później prześladować!

Powiedzmy, że każdy wiersz w tablicy multi wygląda następująco: name, 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);
Potrzebujesz rzeczy w porządku alfabetycznym?
foreach ($sorted_names as $sorted_name) {
    $name_stuff = explode(',',$sorted_name);
    // use your $name_stuff[0] 
    // use your $name_stuff[1] 
    // ... 
}
Tak, jest brudny. Ale super łatwe, nie sprawi Głowa Ci eksploduje.
 0
Author: PJ Brunet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-19 21:00:25

Wolę używać array_multisort. Zobacz dokumentację tutaj .

 -1
Author: Tim Boland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-03 03:59:30