Çok boyutlu bir diziye CSV verilerim yüklendi. Bu şekilde, her "satır" bir kayıttır ve her "sütun" aynı türde veriyi içerir. CSV dosyamı yüklemek için aşağıdaki işlevi kullanıyorum.
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;
}
Satırları yeniden düzenleyecek şekilde sıralamak için bir sütun belirtmem gerekiyor. Sütunlardan biri Y-m-d H:i:s
biçiminde tarih bilgisi içeriyor ve en son tarihin ilk satır olduğu durumla sıralama yapabilmek istiyorum.
array_multisort () kullanabilirsiniz.
Böyle bir şey dene:
foreach ($mdarray as $key => $row) {
// replace 0 with the field's index/key
$dates[$key] = $row[0];
}
array_multisort($dates, SORT_DESC, $mdarray);
PHP> = 5.5.0 için sıralanacak sütunu çıkartmanız yeterlidir. Döngüye gerek yok:
array_multisort(array_column($mdarray, 0), SORT_DESC, $mdarray);
Buraya kendi çözümümü eklemek istiyorum, çünkü diğer cevapların sunmadığı özellikler sunuyor.
Spesifik olarak, bu çözeltinin avantajları şunları içerir:
DateTime
örneği).usort
veya uasort
).array_multisort
kullanmaz: array_multisort
uygun olsa da, sıralamadan önce tüm giriş verilerinizin bir yansıtma oluşturmasına bağlıdır. Bu zaman ve hafıza tüketir ve veri kümeniz büyükse basitçe yasaklayıcı olabilir.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
};
}
Bu bölüm boyunca bu örnek veri setini sıralayan bağlantılar sağlayacağım:
$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'),
);
make_comparer
işlevi, istenen sırayı tanımlayan değişken sayıda değişken kabul eder ve bağımsız değişken olarak usort
veya uasort
için kullanmanız gereken bir işlev döndürür.
En basit kullanım örneği, veri öğelerini karşılaştırmak için kullanmak istediğiniz anahtarı vermektir. Örneğin, $data
öğesini name
öğesine göre sıralamak için
usort($data, make_comparer('name'));
Maddeler sayısal olarak dizine alınmış dizilerse, tuş bir sayı da olabilir. Söz konusu örnek için, bu
usort($data, make_comparer(0)); // 0 = first numerically indexed column
make_comparer
dosyasına ek parametreler ileterek birden fazla sıralama sütunu belirleyebilirsiniz. Örneğin, "sayı" ve ardından sıfır dizinli sütuna göre sıralamak için:
usort($data, make_comparer('number', 0));
Basit bir dize yerine bir dizi olarak bir sıralama sütunu belirtirseniz daha gelişmiş özellikler kullanılabilir. Bu dizi sayısal olarak dizine eklenmeli ve bu öğeleri içermelidir:
0 => the column name to sort on (mandatory)
1 => either SORT_ASC or SORT_DESC (optional)
2 => a projection function (optional)
Bu özellikleri nasıl kullanabileceğimizi görelim.
Azalan ada göre sıralamak için:
usort($data, make_comparer(['name', SORT_DESC]));
Azalan numaraya ve sonra azalan adına göre sıralamak için:
usort($data, make_comparer(['number', SORT_DESC], ['name', SORT_DESC]));
Bazı senaryolarda, değerleri sıralamaya iyi borç vermeyen bir sütuna göre sıralamanız gerekebilir. Örnek veri kümesindeki "doğum günü" sütunu bu açıklamaya uyar: doğum günlerini dizelerle karşılaştırmanın anlamı yoktur (örneğin, "01/01/1980", "10/10/1970" den önce gelir). Bu durumda, projenin gerçek verinin doğrudan istenen anlambilimiyle karşılaştırılabileceği bir forma nasıl belirtileceğini belirtmek istiyoruz.
Projeksiyonlar herhangi bir tür çağrılabilir olarak belirtilebilir: karakter dizileri, diziler veya adsız işlevler. Bir argümanın bir argümanı kabul ettiği ve öngörülen biçimini geri verdiği varsayılır.
Projeksiyonların usort
ve ailesi ile kullanılan özel karşılaştırma işlevlerine benzemekle birlikte, daha basit oldukları (yalnızca bir değeri diğerine dönüştürmeniz gerekir) ve önceden make_comparer
içinde oluşturulan tüm işlevlerden yararlanmaları gerektiğine dikkat edilmelidir.
Örnek veri kümesini projeksiyon olmadan sıralayalım ve ne olacağını görelim:
usort($data, make_comparer('birthday'));
Bu istenen sonuç değildi. Fakat date_create
'ı projeksiyon olarak kullanabiliriz:
usort($data, make_comparer(['birthday', SORT_ASC, 'date_create']));
İstediğimiz doğru sıra bu.
Projeksiyonların başarabileceği daha birçok şey var. Örneğin, büyük/küçük harf duyarlı bir sıralama elde etmenin hızlı bir yolu projeksiyon olarak strtolower
kullanmaktır.
Bununla birlikte, eğer veri kümeniz büyükse projeksiyonları kullanmamanın daha iyi olacağını söylemeliyim: bu durumda tüm verilerinizi elle önceden yansıtmak ve sonra bir projeksiyon kullanmadan sıralamak çok daha hızlı olacaktır, bununla birlikte işlem daha iyi olacaktır. Daha hızlı sıralama hızı için arttırılmış bellek kullanımı.
Son olarak, tüm özellikleri kullanan bir örnek: ilk önce azalan numaraya, ardından doğum gününe göre artan sayıya göre sıralar:
usort($data, make_comparer(
['number', SORT_DESC],
['birthday', SORT_ASC, 'date_create']
));
sort ile. İşte farklı sütunlar için kullanabileceğiniz genel bir çözüm:
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;
}
}
İlk sütuna göre sıralamak için:
$sorter = new TableSorter(0); // sort by first column
$mdarray = $sorter->sort($mdarray);
İşte uasort () ve anonim bir geri çağırma işlevi (kapatma) kullanan başka bir yaklaşım. Bu işlevi düzenli olarak kullandım. PHP 5.3 gerekli - daha fazla bağımlılık yok!
/**
* 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' ) );
Bu sorunun sorulmasından ve yanıtlanmasından bu yana 2 yıl geçtiğini biliyorum, fakat işte iki boyutlu bir diziyi sıralayan başka bir işlev. Sıralamak için birden fazla anahtar (yani sütun adı) girmenize izin veren değişken sayıda argüman kabul eder. PHP 5.3 gerekli.
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;
}
Burada deneyin: 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/
“Usort” işlevi cevabınızdır.
http://php.net/usort
İşte bir veya daha fazla alanı sıralayacak bir php4/php5 sınıfı:
// 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'));
TableSorter sınıfını çalıştırmadan önce, Shinhan 'ın sağladığı şeye dayanarak bir işlev buldum.
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;
}
Birkaç popüler array_multisort () ve usort () cevaplarını denedim ve hiçbiri benim için çalışmadı. Veriler karıştı ve kod okunamıyor. İşte hızlı ve kirli bir çözüm. UYARI: Bunu, yalnızca bir hileli sınırlayıcının sizi daha sonra rahatsız etmek için geri dönmeyeceğinden eminseniz kullanın!
Diyelim ki çoklu dizinizdeki her satır şöyle görünür: 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);
Eşyalarına alfabetik sıraya göre mi ihtiyacınız var?
foreach ($sorted_names as $sorted_name) {
$name_stuff = explode(',',$sorted_name);
// use your $name_stuff[0]
// use your $name_stuff[1]
// ...
}
Evet, kirli. Ama süper kolay, kafanı patlatmayacak.