Bagaimana cara Mengurutkan Array Multidimensi dalam PHP

Saya telah CSV data dimuat ke dalam sebuah array multidimensi. Dengan cara ini masing-masing "baris" adalah catatan dan masing-masing "kolom" berisi satu jenis data yang sama. Saya menggunakan fungsi di bawah ini untuk memuat 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;
}

Aku harus mampu untuk menentukan kolom untuk mengurutkan sehingga menata kembali baris. Salah satu kolom yang berisi informasi tanggal dalam format Y-m-d H:i:s dan aku ingin menjadi mampu memilah dengan tanggal terakhir menjadi baris pertama.

Mengomentari pertanyaan (3)

Memperkenalkan: yang sangat umum solusi untuk PHP 5.3+

I 'd ingin menambahkan saya sendiri solusi di sini, karena menawarkan fitur-fitur yang lain jawaban tidak.

Secara khusus, keuntungan dari solusi ini meliputi:

  1. It's reusable: anda menentukan jenis kolom sebagai variabel bukan hardcoding itu.
  2. It's fleksibel: anda dapat menentukan beberapa jenis kolom (sebanyak yang anda inginkan) -- kolom tambahan yang digunakan sebagai tiebreakers antara barang-barang yang awalnya membandingkan sama.
  3. It's reversibel: anda dapat menentukan semacam itu harus dibalik -- secara individual untuk masing-masing kolom.
  4. It's extensible: jika set data yang berisi kolom-kolom yang tidak dapat dibandingkan dalam "bodoh" cara (misalnya tanggal string) anda juga dapat menentukan bagaimana mengkonversi barang-barang ini ke nilai yang dapat diperbandingkan secara langsung (misalnya DateTime contoh).
  5. It's asosiatif jika anda ingin: kode ini mengurus menyortir barang-barang, tapi anda ** pilih yang sebenarnya semacam fungsi (usort atau uasort).
  6. Akhirnya, tidak menggunakan array_multisort: sementara array_multisort lebih nyaman, hal ini tergantung pada menciptakan sebuah proyeksi dari semua input data sebelum sorting. Ini membutuhkan waktu dan memori, dan mungkin akan cukup mahal jika data set yang besar.

Kode

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

Cara menggunakan

Seluruh bagian ini saya akan memberikan link yang semacam ini contoh data set:

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

Dasar-dasar

Fungsi make_comparer menerima sejumlah variabel argumen yang menentukan jenis dan mengembalikan fungsi yang anda diharapkan untuk digunakan sebagai argumen untuk usort atau uasort.

Yang paling sederhana menggunakan kasus ini untuk lulus dalam kunci yang anda 'd digunakan untuk membandingkan data item. Misalnya, untuk semacam $data oleh nama item yang anda akan lakukan

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

Melihatnya dalam tindakan.

Kunci juga dapat menjadi nomor satu jika barang numerik array diindeks. Misalnya dalam pertanyaan, ini akan menjadi

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

Melihatnya dalam tindakan.

Beberapa jenis kolom

Anda dapat menentukan beberapa jenis kolom dengan melewatkan parameter tambahan untuk make_comparer. Misalnya, untuk mengurutkan berdasarkan "nomor" dan kemudian oleh-nol kolom:

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

Melihatnya dalam tindakan.

Fitur canggih

Lebih banyak fitur canggih yang tersedia jika anda menentukan jenis kolom sebagai array bukan sebuah string sederhana. Array ini harus diindeks secara numerik, dan harus berisi barang-barang ini:

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

Let's melihat bagaimana kita dapat menggunakan fitur ini.

Urut terbalik

Untuk mengurutkan berdasarkan nama descending:

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

Melihatnya dalam tindakan.

Untuk mengurutkan berdasarkan jumlah menurun dan kemudian dengan nama turun:

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

Melihatnya dalam tindakan.

Custom proyeksi

Dalam beberapa skenario anda mungkin perlu untuk mengurutkan berdasarkan kolom dan nilai-nilai yang tidak meminjamkan baik untuk menyortir. "ulang tahun" kolom pada data sampel yang ditetapkan sesuai dengan deskripsi ini: itu tidak masuk akal untuk membandingkan ulang tahun sebagai string (karena misalnya "01/01/1980" sebelum "10/10/1970"). Dalam hal ini kami ingin untuk menentukan bagaimana untuk proyek data aktual dengan bentuk yang bisa dapat dibandingkan secara langsung dengan yang diinginkan semantik.

Proyeksi dapat ditetapkan sebagai jenis callable: seperti string, array, atau fungsi anonim. Proyeksi ini diasumsikan untuk menerima satu argumen dan kembali diproyeksikan bentuk.

Perlu dicatat bahwa sementara proyeksi mirip dengan custom perbandingan fungsi-fungsi yang digunakan dengan usort dan keluarga, mereka sederhana (anda hanya perlu untuk mengkonversi nilai satu sama lain) dan mengambil keuntungan dari semua fungsi yang sudah dipanggang ke make_comparer.

Let's mengurutkan data contoh set tanpa proyeksi dan lihat apa yang terjadi:

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

Melihatnya dalam tindakan.

Itu bukan hasil yang diinginkan. Tapi kita dapat menggunakan date_create sebagai proyeksi:

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

Melihatnya dalam tindakan.

Ini adalah urutan yang benar yang kita inginkan.

Ada banyak hal yang proyeksi dapat mencapai. Misalnya, cara yang cepat untuk mendapatkan kasus-sensitif semacam ini adalah untuk menggunakan strtolower sebagai proyeksi.

Yang mengatakan, saya juga harus menyebutkan bahwa itu's lebih baik untuk tidak menggunakan proyeksi jika anda set data yang besar: dalam hal itu akan menjadi jauh lebih cepat untuk memproyeksikan semua data anda secara manual ke depan dan kemudian mengurutkan tanpa menggunakan proyeksi, meskipun demikian akan perdagangan peningkatan penggunaan memori yang lebih cepat semacam kecepatan.

Akhirnya, di sini adalah contoh yang menggunakan semua fitur: pertama jenis dengan jumlah menurun, maka dengan ulang tahun ascending:

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

Melihatnya dalam tindakan.

Komentar (26)
Larutan

Anda dapat menggunakan array_multisort()

Mencoba sesuatu seperti ini:

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

array_multisort($dates, SORT_DESC, $mdarray);

Untuk PHP >= 5.5.0 hanya mengekstrak kolom untuk mengurutkan berdasarkan. Tidak perlu untuk loop:

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

Dengan usort. Berikut ini's solusi yang umum, yang dapat anda gunakan untuk kolom yang berbeda:

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

Untuk mengurutkan berdasarkan kolom pertama:

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

Beberapa baris pengurutan menggunakan penutupan

Berikut ini's pendekatan lain menggunakan uasort() dan anonim fungsi callback (penutupan). I've digunakan fungsi itu secara teratur. PHP 5.3 diperlukan – tidak ada lagi ketergantungan!

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

Aku tahu itu's 2 tahun sejak pertanyaan ini diajukan dan dijawab, tapi di sini's fungsi lain yang macam array dua dimensi. Ia menerima sejumlah variabel argumen, yang memungkinkan anda untuk lulus di lebih dari satu key (yaitu kolom nama) untuk mengurutkan berdasarkan. PHP 5.3 diperlukan.


function sort_multi_array ($array, $key)
{
  $keys = array();
  for ($i=1;$i
Komentar (2)
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/

Komentar (0)

"Usort" fungsi adalah jawaban anda. http://php.net/usort

Komentar (1)

Berikut ini adalah php4/php5 kelas yang akan memilah satu atau lebih bidang-bidang:

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

Sebelum aku bisa mendapatkan TableSorter kelas untuk menjalankan saya telah datang dengan fungsi yang didasarkan pada apa yang Shinhan telah disediakan.

fungsi sort2d_bycolumn($array, $kolom, $metode $has_header)
{
if ($has_header) $header = array_shift($array);
foreach ($array as $key => $row) {
$narray[$key] = $row[$kolom]; 
}
array_multisort($narray, $metode, $array);
if ($has_header) array_unshift($array, $header);
kembali $array;
}
  • $array adalah MD Array yang ingin anda urutkan.
  • $kolom adalah kolom yang ingin anda urutkan.
  • $metode adalah cara anda ingin mengurutkan dilakukan, seperti SORT_DESC
  • $has_header set ke true jika baris pertama berisi header nilai-nilai yang anda don't ingin diurutkan.
Komentar (0)

Aku mencoba beberapa tempat array_multisort() dan usort() jawaban dan tidak satupun dari mereka bekerja untuk saya. Data hanya akan campur aduk dan kode terbaca. Berikut ini's cepat kotor solusi. PERINGATAN: Hanya gunakan ini jika anda're yakin nakal pembatas won't datang kembali untuk menghantui anda nanti!

Let's mengatakan setiap baris dalam array multi terlihat seperti: nama, 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);

Perlu anda kembali hal-hal dalam urutan abjad?

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

Ya, itu's kotor. Tapi super mudah, tidak't membuat kepala anda meledak.

Komentar (0)

Saya lebih suka menggunakan array_multisort. Lihat dokumentasi di sini.

Komentar (0)