Çok Boyutlu Dizi Değere Göre Nasıl Sıralanır?


1129

Bu diziyi "order" anahtarının değerine göre nasıl sıralayabilirim? Değerler şu anda sıralı olmasına rağmen, her zaman olmayacaklardır.

Array
(
    [0] => Array
        (
            [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
            [title] => Flower
            [order] => 3
        )

    [1] => Array
        (
            [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
            [title] => Free
            [order] => 2
        )

    [2] => Array
        (
            [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
            [title] => Ready
            [order] => 1
        )
)


en hızlı yol, hem tarayıcıda hem de düğümde yerel olarak çalışan, her türlü girişi, hesaplanan alanları ve özel sıralama düzenlerini destekleyen izomorfik sıralama dizisi modülünü kullanmaktır .
Lloyd

Yanıtlar:


1733

Bir usort deneyin , Hala PHP 5.2 veya önceki bir sürümdeyseniz , önce bir sıralama işlevi tanımlamanız gerekir:

function sortByOrder($a, $b) {
    return $a['order'] - $b['order'];
}

usort($myArray, 'sortByOrder');

PHP 5.3'ten başlayarak, anonim bir işlev kullanabilirsiniz:

usort($myArray, function($a, $b) {
    return $a['order'] - $b['order'];
});

Ve son olarak PHP 7 ile uzay gemisi operatörünü kullanabilirsiniz :

usort($myArray, function($a, $b) {
    return $a['order'] <=> $b['order'];
});

Bunu çok boyutlu sıralamaya genişletmek için, birinci sıfırsa, ikinci / üçüncü sıralama öğelerine bakın - aşağıda en iyi açıklanmıştır. Bunu alt öğelerde sıralama için de kullanabilirsiniz.

usort($myArray, function($a, $b) {
    $retval = $a['order'] <=> $b['order'];
    if ($retval == 0) {
        $retval = $a['suborder'] <=> $b['suborder'];
        if ($retval == 0) {
            $retval = $a['details']['subsuborder'] <=> $b['details']['subsuborder'];
        }
    }
    return $retval;
});

Anahtar ilişkilendirmeleri korumanız gerekiyorsa, kullanın uasort()- kılavuzdaki dizi sıralama işlevlerinin karşılaştırmasına bakın


2
İfadem biraz kapalı, düzenleyeceğim. Demek istediğim, PHP 5.3'te değilseniz, sadece bu belirli sıralama için özel bir işlev oluşturmanız gerekir (Bu bir şekilde çok zarif değil). Aksi takdirde, burada anonim bir işlev kullanabilirsiniz.
Christian Studer

23
@Jonathan: PHP'nin yaptığı işlerin çoğunu gerçekten göremezsiniz. Diziyi alır ve bu kullanıcı tanımlı işleve ilettiği iki öğeyle başlar. Bu durumda işleviniz bunları karşılaştırmaktan sorumludur: İlk öğe ikinciden büyükse, pozitif bir tamsayı döndürün, daha küçükse, negatif olanı döndürün. Eşdeğerlerse, 0 döndürün. PHP daha sonra işlevinize iki öğe daha gönderir ve dizi sıralanıncaya kadar bunu yapmaya devam eder. Buradaki işlev çok kısadır, tamsayıları karşılaştırmazsanız çok daha karmaşık olabilir.
Christian Studer

61
Koru: uasort()dizi tuşlarını korumak istiyorsanız kullanın.
thaddeusmt

15
Sıralanabilir değerler ondalık sayılarsa dikkatli olun. Sıralama işlevi $ a = 1 ve $ b = 0.1 ise, fark 0.9'dur, ancak işlev bir int döndürür, bu durumda 0, bu nedenle $ a ve $ b eşit kabul edilir ve yanlış sıralanır. $ A'nın $ b veya daha büyük olup olmadığını karşılaştırmak ve buna göre -1, 1 veya 0 döndürmek daha güvenilirdir.
Greenlandi

37
Öğrenmem biraz zaman aldı. Ters sırayı (DESC) sıralamak için $ a ve $ b arasında geçiş yapabilirsiniz. Yani $ b ['sipariş'] - $ a ['sipariş']
JanWillem

285
function aasort (&$array, $key) {
    $sorter=array();
    $ret=array();
    reset($array);
    foreach ($array as $ii => $va) {
        $sorter[$ii]=$va[$key];
    }
    asort($sorter);
    foreach ($sorter as $ii => $va) {
        $ret[$ii]=$array[$ii];
    }
    $array=$ret;
}

aasort($your_array,"order");

7
@ noc2spam Size yardımcı olmaktan memnuniyet duyarız, ancak muhtemelen daha verimli ve kesinlikle daha düzenli olan studer'in önerilerini izlemeyi düşünün !
o0 '.

1
@Lohoris emin ahbap Ben de kontrol ediyorum. Bu soruyu bulamazsam dün ofiste daha zor bir gün olurdu :-)
Gogol

hmm bir cevap ekleyemem .. iyi buraya koydum çünkü bu aptal noktalara ihtiyacım yok: bu yüzden çok boyutlu bir sıralama için (neredeyse) aynı şey (srry yapıştır ve yeniden biçimlendirmek zorundasın): function aasort (& $ array , $ key1, $ key2, $ key3) {$ sorter = array (); $ ret = dizisi (); ($ dizi) reset; foreach ($ dizi olarak $ ii => $ va) {$ sıralayıcı [$ ii] = getPrice ($ va [$ key1] [$ key2] [$ key3]); } arsort ($ sıralayıcı); foreach ($ sıralayıcı $ ii => $ va) {$ ret [$ ii] = $ dizi [$ ii]; } $ dizi = $ ret; }
Jaxx0rr

3
Yukarıdaki cevaba göre uygulamak çok daha kolay
Marcel

1
HARİKASIN!! PHP 7.2 GİBİ ÇALIŞIYOR
ÇALIŞMAK

270

Bu işlevi kullanıyorum:

function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) {
    $sort_col = array();
    foreach ($arr as $key=> $row) {
        $sort_col[$key] = $row[$col];
    }

    array_multisort($sort_col, $dir, $arr);
}


array_sort_by_column($array, 'order');

3
Çok iyi çalışıyor. Eşsiz çözüm bir sıralama yönü ekleyebilmektir. Teşekkürler!
Ivo Pereira

2
Sıralama yönlerini ve birçok ek özelliği destekleyen bir alternatif için, buradaki cevabımıza bir göz atmak isteyebilirsiniz - ayrıca kullanmama avantajı vardır array_multisortve böylece önceden yer değiştirmesi gerekmez $sort_col, zamandan ve hafızadan tasarruf etmenizi sağlar .
Jon

Benim için harika çalışıyor, ama ... neden &$arrsadece yerine belirtmek gerekiyor $arr?
Radu Murzea

2
@RaduMurzea böylece dizi referans tarafından geçirilir ve kopya alma işlevi yerine işlev tarafından değiştirilebilir
Tom Haigh

1
@AdrianP. : dizi referans olarak iletilir, böylece sıralanmış bir kopyayı döndürmek yerine geçirilen diziyi değiştirir
Tom Haigh

72

Genellikle usort kullanıyorum ve kendi karşılaştırma fonksiyonumu geçiyorum . Bu durumda, çok basit:

function compareOrder($a, $b)
{
  return $a['order'] - $b['order'];
}
usort($array, 'compareOrder');

Uzay gemisi operatörünü kullanan PHP 7'de:

usort($array, function($a, $b) {
    return $a['order'] <=> $b['order'];
});

4
Lanet olsun, 30 saniye daha yavaştım. Yine de $ a - $ b değil mi?
Christian Studer

3
Bunu hep yanlış anlarım. Kılavuzdan düşünmeme izin verin: eğer birinci argüman ikinciden daha az kabul edilirse dönüş değeri sıfırdan küçük olmalıdır. Yani eğer $a['order']3 ve $b['order']6, ben dönecektir -3. Doğru?
Jan Fabry

3
Peki, b - a döndürürsünüz, böylece 3 olur. Böylece yanlış sıralanır.
Christian Studer

26
Ah. TAMAM. Kafanızdaki fikrin ürettiğiniz kelimelerle eşleşmediği mantıksal olmayan aritmetik kullanıyordum. Bu en çok Cuma öğleden sonraları incelenir.
Jan Fabry

yukarıdaki bazı durumlarda cevap yanlış sonuç döndürür .. referans stackoverflow.com/questions/50636981/…
Bilal Ahmed

45

Bunu başarmak için bir yaklaşım şöyle olacaktır

    $new = [
              [
                'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4',
                'title' => 'Flower',
                'order' => 3,
              ],

              [
                'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594',
                'title' => 'Free',
                'order' => 2,
              ],

              [
                'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b',
                'title' => 'Ready',
                'order' => 1,
              ],
    ];

    $keys = array_column($new, 'order');

    array_multisort($keys, SORT_ASC, $new);

    var_dump($new);

Sonuç:

    Array
    (
        [0] => Array
            (
                [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
                [title] => Ready
                [order] => 1
            )

        [1] => Array
            (
                [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
                [title] => Free
                [order] => 2
            )

        [2] => Array
            (
                [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
                [title] => Flower
                [order] => 3
            )

    )

18

Diziyi "title" tuşunun değerine göre sıralamak için şunu kullanın:

uasort($myArray, function($a, $b) {
    return strcmp($a['title'], $b['title']);
});

strcmp dizeleri karşılaştırır.

uasort () , dizi anahtarlarını tanımlandıkları gibi korur.


strcmp varchar türleri için önemli bir yardım, kısa ve hızlı bu cevabı sevdim
StudioX

17
$sort = array();
$array_lowercase = array_map('strtolower', $array_to_be_sorted);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);

Bu, hem büyük hem de küçük harfli alfabe ile ilgilenir.


4
Bu belirli bir dizi anahtarına göre sıralama sorusuna nasıl cevap verir?
Seano

12

Kullanımı array_multisort(),array_map()

array_multisort(array_map(function($element) {
      return $element['order'];
  }, $array), SORT_ASC, $array);

print_r($array);

DEMO


Bu yaklaşımın bir uyarı vereceğini unutmayın. array_multisortreferans ilk parametre.
Kami Yang

5

En esnek yaklaşım bu yöntemi kullanmak olacaktır.

Arr::sortByKeys(array $array, $keys, bool $assoc = true): array

İşte nedeni:

  • Herhangi bir tuşa göre sıralayabilirsiniz ( 'key1.key2.key3'veya gibi yuvalanmış ['k1', 'k2', 'k3'])

  • İlişkilendirilebilir dizilerde değil ilişkisel dizilerde çalışır ( $assocbayrak)

  • Referans kullanmaz - yeni sıralı dizi döndürür

Sizin durumunuzda bu kadar basit olurdu:

$sortedArray = Arr::sortByKeys($array, 'order');

Bu yöntem bu kütüphanenin bir parçasıdır .


1

Şunu kabul edelim: php, her dizi sıralama senaryosunu düzgün bir şekilde işlemek için basit bir kutu işlevine sahip DEĞİLDİR.

Bu rutin sezgiseldir, bu da daha hızlı hata ayıklama ve bakım anlamına gelir:

// automatic population of array
$tempArray = array();
$annotations = array();
// ... some code
// SQL $sql retrieves result array $result 
// $row[0] is the ID, but is populated out of order (comes from 
// multiple selects populating various dimensions for the same DATE 
// for example
while($row = mysql_fetch_array($result)) {
    $needle = $row[0];
    arrayIndexes($needle);  // create a parallel array with IDs only
    $annotations[$needle]['someDimension'] = $row[1]; // whatever
}
asort($tempArray);
foreach ($tempArray as $arrayKey) {
    $dataInOrder = $annotations[$arrayKey]['someDimension']; 
    // .... more code
}

function arrayIndexes ($needle) {
    global $tempArray;
    if (!in_array($needle,$tempArray)) {
        array_push($tempArray,$needle);
    }
}

4
"Kabul edelim: php, her dizi sıralama senaryosunu düzgün bir şekilde işlemek için basit bir kutu işlevine sahip DEĞİLDİR." Usort / ksort / asort tam olarak ^^ için tasarlandı
Ben Cassinat

3
Aslında PHP , her dizi sıralama senaryosunu işlemek için kullanılabilecek birçok sıralama işlevine sahiptir.
axiac

Hata ayıklama ve bakım ile ilgili olarak, kullanımı globalbüyük bir kırmızı bayraktır ve genellikle önerilmez . Neden mysql_fetch_arrayOP'nin kaynak dizisi yerine bu soru için gösteriliyor ve kodunuzun ne yaptığının ve sonucun ne olmasını bekleyebileceğinin açıklaması yok? Genel olarak, bu istenen sonuca ulaşmada çok karmaşık bir yaklaşımdır.
fyrye

@tonygil Yanıtınızdan ve OP'nin veri kümesinden beklenen sonuçlarınızın ne olduğunu belirleyemiyorum. Sizin için açık olabilir, ancak cevabınızın OP'nin sorusuna nasıl cevap verdiğini bilmiyorum. Bununla birlikte, bkz. Bkz: 3v4l.org/FEeFC Kullanmak yerine referans yoluyla iletebilirsiniz. Bu, genel olarak değiştirilip erişilebilen değişken yerine açıkça tanımlanmış bir değişken üretir. global
fyrye

0

Çok boyutlu diziyi aşağıdaki gibi birden çok değer için de sıralayabilirsiniz

$arr = [
    [
        "name"=> "Sally",
        "nick_name"=> "sal",
        "availability"=> "0",
        "is_fav"=> "0"
    ],
    [
        "name"=> "David",
        "nick_name"=> "dav07",
        "availability"=> "0",
        "is_fav"=> "1"
    ],
    [
        "name"=> "Zen",
        "nick_name"=> "zen",
        "availability"=> "1",
        "is_fav"=> "0"
    ],
    [
        "name"=> "Jackson",
        "nick_name"=> "jack",
        "availability"=> "1",
        "is_fav"=> "1"
    ],
    [
        "name"=> "Rohit",
        "nick_name"=> "rod",
        "availability"=> "0",
        "is_fav"=> "0"
    ],

];

ile

usort($arr,function($a,$b){
    $c = $b['is_fav'] - $a['is_fav'];
    $c .= $b['availability'] - $a['availability'];
    $c .= strcmp($a['nick_name'],$b['nick_name']);
    return $c;
});

Çıktı kullanarak print_r($arr):

Array
(
    [0] => Array
        (
            [name] => Jackson
            [nick_name] => jack
            [availability] => 1
            [is_fav] => 1
        )

    [1] => Array
        (
            [name] => David
            [nick_name] => dav07
            [availability] => 0
            [is_fav] => 1
        )

    [2] => Array
        (
            [name] => Zen
            [nick_name] => zen
            [availability] => 1
            [is_fav] => 0
        )

    [3] => Array
        (
            [name] => Rohit
            [nick_name] => rod
            [availability] => 0
            [is_fav] => 0
        )

    [4] => Array
        (
            [name] => Sally
            [nick_name] => sal
            [availability] => 0
            [is_fav] => 0
        )

)

PS) strcmp kullanmak dizeleri karşılaştırmak için iyi bir seçenek olacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.