PHP nasıl bir çok boyutlu dizi sıralama yok [çoğaltmak]

9 Cevap php

Bu soru burada zaten bir cevabı var:

9 Cevap

Sen kullanabilirsiniz array_multisort()

Böyle bir şey deneyin:

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

array_multisort($dates, SORT_DESC, $mdarray);

Introducing: a very generalized solution for PHP 5.3+

Ben başka bir cevap olmadığını özellikler sunuyor beri, burada kendi çözüm eklemek istiyorum '.

Özel olarak, bu çözeltinin avantajları şunlardır:

  1. Eğer bunun yerine hardcoding bir değişken olarak sıralama sütununu belirtin: Bu reusable bulunuyor.
  2. (Size istediğiniz kadar) birden fazla sıralama sütunları belirleyebilirsiniz - ek sütunlar başlangıçta eşit karşılaştırmak öğeler arasında tiebreakers olarak kullanılır: Bu flexible bulunuyor.
  3. - Her sütun için ayrı ayrı, sıralama tersine gerektiğini belirtebilirsiniz: Bu reversible bulunuyor.
  4. Bu extensible bulunuyor: veri seti de (örneğin doğrudan mukayese edilebilir bir değere bu öğeleri dönüştürmek için nasıl belirleyebilirsiniz bir "aptal" bir şekilde (örneğin tarih dizeleri) karşılaştırıldığında olamaz sütunları içeriyorsa DateTime örneği).
  5. Bu kod sıralama öğelerinden önemser, ama you gerçek sıralama fonksiyonunu (usort veya uasort) seçeneğini seçin: Bu associative if you want bulunuyor.
  6. Son olarak, kullanmak değildir array_multisort: array_multisort uygun ise, bu sıralamadan önce tüm veri girişi bir projeksiyon oluşturma bağlıdır. Bu zaman ve bellek tüketir ve veri kümesi büyükse sadece engelleyici olabilir.

The code

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

How to use

Bu bölüm boyunca ben bu örnek veri seti sıralamak bağlantıları sağlayacak:

$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 basics

Fonksiyonu make_comparer istenen sıralama tanımlamak bağımsız değişken bir dizi kabul eder ve usort veya uasort için argüman olarak kullanmak gerekiyor bir işlevi döndürür.

Basit kullanımı durumda size 'veri öğeleri karşılaştırmak için kullanmak istiyorum anahtarında geçmektir. Örneğin, sen yapardın name öğesi tarafından $data sıralamak için

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

See it in action .

Öğeleri sayısal indisli diziler ise anahtar da bir sayı olabilir. Söz konusu örnekte, bu olur

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

See it in action .

Multiple sort columns

Sen make_comparer ek parametreler ileterek birden fazla sıralama sütun belirtebilirsiniz. Örneğin, "sayı" göre sıralamak ve daha sonra sıfır endeksli sütuna tarafından:

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

See it in action .

Advanced features

Eğer bir dizinin yerine basit bir dizge olarak bir sıralama sütunu belirtmek eğer daha gelişmiş özellikler bulunmaktadır. Bu dizi sayısal endeksli olmalıdır 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)

Kullanıcının bu özelliklerini nasıl kullanılacağını görelim.

Reverse sort

Adı azalan göre sıralamak için:

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

See it in action .

Numarası azalan tarafından ve daha sonra isim azalan göre sıralamak için:

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

See it in action .

Custom projections

Bazı senaryolarda, değerleri sıralama iyi borç yoktur bir sütuna göre sıralamak gerekebilir. Örnek veri seti "doğum günü" sütunu bu tanıma uyan: (örneğin "01/01/1980", "1970/10/10" önce gelir çünkü) dizeleri gibi doğum günlerini karşılaştırmak mantıklı değil. Bu durumda biz belirtmek istiyorum nasıl can istenen semantik ile doğrudan karşılaştırıldığında bir form project gerçek veri için.

Projeksiyonlar callable herhangi bir türü olarak belirtilebilir: dizeleri, diziler veya anonim fonksiyonlar gibi. Bir projeksiyon bir argüman kabul ve öngörülen formu varsayılır.

Bu projeksiyonlar usort ve ailesi ile kullanılan özel karşılaştırma işlevlerine benzer iken, bunlar basit vardır (sadece başka bir değere dönüştürmek gerekir) ve zaten içine pişmiş tüm işlevsellikten yararlanmak unutulmamalıdır make_comparer.

Adlı bir projeksiyon olmadan seti örnek verileri sıralamak ve ne görelim:

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

See it in action .

Yani istenen sonuç değildi. Ama biz bir projeksiyon olarak date_create kullanabilirsiniz:

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

See it in action .

Bu, bu istedik doğru emirdir.

Projeksiyonları elde edebilirsiniz ki daha çok şey vardır. Örneğin, bir harf duyarsız bir tür almak için hızlı bir şekilde bir projeksiyon olarak strtolower kullanmaktır.

O dedi, ben de senin veri seti büyük ise o projeksiyonlar kullanmak daha iyi olduğunu belirtmek gerekir: bu durumda, bunu yaparken de, bir projeksiyon kullanmadan elle ön ve ardından sıralama tüm verilerinizi proje için çok daha hızlı olurdu ticaret yapacak Daha hızlı sıralama hızı artan bellek kullanımı.

Son olarak, burada tüm özelliklerini kullanan bir örnek: O sayı Azalan ilk sıralar, doğum günü Artan:

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

See it in action .

Ile usort. Burada genel bir çözüm, farklı sütunlar için kullanabileceğiniz, var:

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

Ben bu soruyu sordu ve cevap oldu bu yana 2 yıl var biliyorum, ama burada iki boyutlu bir diziyi sıralar başka bir fonksiyon. Bu göre sıralamak için birden fazla anahtar (yani sütun adı) geçmesine izin, bağımsız değişken bir dizi kabul eder. PHP 5.3 gereklidir.

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

Burada bir veya daha fazla alan sıralamak bir PHP4/PHP5 sınıftır:

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

Multiple row sorting using a closure

İşte uasort kullanarak başka yaklaşım () ve bir anonim geri arama fonksiyonu (kapatma) bulunuyor. Ben düzenli olarak bu işlevi kullandım. PHP 5.3 required - artık bağımlılıkları!

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

Ben çalıştırmak için tablesorter sınıf alabilir önce Shinhan vermişti ne dayalı bir fonksiyonu ile geldi vardı.

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;
  }
  • $ Dizi sıralamak istediğiniz MD Array.
  • $ Sütun sıralamak istediğiniz sütun.
  • $ Yöntem sıralama gibi SORT_DESC gibi, gerçekleştirilmesini istediğiniz nasıl
  • Ilk satır size sıralanan istemiyorum başlık değerlerini içeriyorsa $ has_header ayarlanır true.

İşte benim uygulamasıdır. Ben kategori girişleri dahil bir kategori nesnesi vardı. Ben bir alt-dizi değeri tarafından bu kayıtlar sıralamak istedim. İşte ben bu konuda böyle gitti.

$ In_cat_team_arr ayıklanmamış dizisi nerede

<?php
//sort multidimensional array by $order_in_category
if (count ($in_cat_team_arr) > 0) {
    foreach ($in_cat_team_arr as $key => $row) {
        $order_in_category[$key]  = $row[0];//[0] is $order_in_category
    }
    array_multisort($order_in_category, SORT_ASC, $in_cat_team_arr);
}

foreach ($in_cat_team_arr as $team_mem) {
    //loop through the sorted array here
}

Bu benim için güzel çalışıyor.

Ama bir sorum var. Anahtar adı yerine indeks (örneğin $ row ['my_key_name'] yerine $ row [0]) kullanmak için herhangi bir yolu var mı? Bunu denedim ve şifreli var.

Ben birkaç popüler array_multisort () ve usort () cevaplar çalıştı ve bunların hiçbiri benim için çalıştı. Veri sadece karmakarışık ve kod okunamaz olur. Burada hızlı bir kirli bir çözümdür. UYARI: Kötü niyetli bir sınırlayıcı sonra uğrak geri gelmeyecek emin değilseniz sadece bu kullanın!

Isim, stuff1, stuff2: senin çok dizide her satır gibi görünüyor diyelim:

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

Geri alfabetik sırayla Eşyalarını 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, o kirli. Ama süper kolay, başınızı patlayabilir yapmaz.