it-swarm-tr.com

Çok Boyutlu Bir Diziyi PHP içinde nasıl sıralarım?

Ç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.

197
Melikoth

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);
210
Shinhan

Tanıtımı: PHP 5.3+ için çok genel bir çözüm

Buraya kendi çözümümü eklemek istiyorum, çünkü diğer cevapların sunmadığı özellikler sunuyor.

Spesifik olarak, bu çözeltinin avantajları şunları içerir:

  1. yeniden kullanılabilir : sıralama sütununu sabit kodlamak yerine değişken olarak belirtirsiniz.
  2. Esnek : Birden çok sıralama sütunu (istediğiniz kadar) belirleyebilirsiniz - ek sütunlar, başlangıçta eşit olan öğeler arasında tiebreaker olarak kullanılır.
  3. Bu geri dönüşümlüdür : sıralamanın tersine çevrileceğini belirtebilirsiniz - her sütun için ayrı ayrı.
  4. Bu genişletilebilir : veri kümesi "aptal" şekilde karşılaştırılamayan sütunlar içeriyorsa (örneğin, tarih dizeleri) bunların nasıl dönüştürüleceğini de belirleyebilirsiniz. doğrudan karşılaştırılabilecek bir değere eşyalar (örneğin, bir DateTime örneği).
  5. İsterseniz ilişkilendiricidir : bu kod öğeleri sıralamaya bakar, ancak siz gerçek sıralamayı seçersiniz işlevi (usort veya uasort).
  6. Son olarak, 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.

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

Nasıl kullanılır

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

Temeller

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

İşlemde görün.

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

İşlemde görün.

Birden çok sıralama sütunu

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

İşlemde görün.

Gelişmiş özellikler

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.

Ters sıralama

Azalan ada göre sıralamak için:

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

İşlemde görün.

Azalan numaraya ve sonra azalan adına göre sıralamak için:

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

İşlemde görün.

Özel projeksiyonlar

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

İşlemde görün.

Bu istenen sonuç değildi. Fakat date_create 'ı projeksiyon olarak kullanabiliriz:

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

İşlemde görün.

İ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']
));

İşlemde görün.

341
Jon

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);
31
troelskn

Bir kapatma kullanarak çoklu satır sıralama

İş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' ) );
10
feeela

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

7
Mike C
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
Kamal

“Usort” işlevi cevabınızdır.
http://php.net/usort

3
Jan Hančič

İş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'));
2
Devon

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;
  }
  • $ array, sıralamak istediğiniz MD Dizisidir.
  • $ column, sıralamak istediğiniz sütundur.
  • $ method, SORT_DESC gibi sıralamanın nasıl yapılmasını istediğinizdir.
  • $ has_header, ilk satır sıralamak istemediğiniz başlık değerleri içeriyorsa true olarak ayarlanır.
0
Melikoth

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.

0
PJ Brunet