PHP'de dizileri ve verileri nasıl sıralayabilirim?


292

Bu soru PHP'de dizileri sıralama hakkındaki sorulara referans olarak hazırlanmıştır. Özel durumunuzun benzersiz ve yeni bir soruya layık olduğunu düşünmek kolaydır, ancak çoğu aslında bu sayfadaki çözümlerden birinin küçük varyasyonlarıdır.

Sorunuz bunun bir kopyası olarak kapalıysa, lütfen sorunuzun yalnızca aşağıdakilerden neden önemli ölçüde farklı olduğunu açıklayabiliyorsanız tekrar açılmasını isteyin.

PHP'de bir diziyi nasıl sıralayabilirim? PHP'de karmaşık bir diziyi
nasıl sıralayabilirim ? PHP'de bir nesne dizisini nasıl sıralayabilirim?


  1. Temel tek boyutlu diziler; Dahil. Çok boyutlu diziler, dahil. nesne dizileri; Dahil. Bir diziyi diğerine göre sıralama

  2. SPL ile sıralama

  3. Kararlı sıralama

PHP'nin mevcut işlevleri kullanarak pratik yanıt için (PHP'nin fonksiyonları uygulamak ve sıralama algoritmaları üzerinde akademik in-detay cevap, 1. bkz olabilir , gerçekten gerçekten karmaşık durumlarda gerekir), 2 bakınız.


@jterry Kesinlikle, bu yüzden nihayet kapatmak için iyi bir referans soruya sahip yaptım. Her benzersiz kar tanesi ayrı ayrı cevaplamak kimseye yardımcı olmaz. :)
deceze

3
Bence insanlar sadece php.net'e bir göz atmalılar
Alexander Jardim

@Alex Ha! Kesinlikle. Sorun şu: hiç kimse RTFM. : D
çökme

2
Bu yanıtları zaten aldık, içeriği çoğaltmak (veya yeniden yazmak) yerine her cevabın içindeki en iyi cevapları listelemenizi öneriyorum. Ayrıca, diziler tek tek görülme eğilimindedir, bu nedenle çalışma her durumda çiftlere karşı yakın oy kullanmaya devam etmektedir.
hakre

1
@deceze: Kimse RTFM değilse, kimse de RTFQA - mevcut Soru-Cevap :)
hakre

Yanıtlar:


164

Temel tek boyutlu diziler

$array = array(3, 5, 2, 8);

Uygulanabilir sıralama fonksiyonları:

  • sort
  • rsort
  • asort
  • arsort
  • natsort
  • natcasesort
  • ksort
  • krsort

Bunlar arasındaki fark sadece anahtar / değer ilişkilendirmelerinin tutulması (" a" işlevleri), alçaktan yükseğe veya tersine (" r") sıralanması, değerleri veya anahtarları (" k") sıralayıp sıralamaması ve değerleri nasıl karşılaştırmasıdır. (" nat" - normal). Genel bir bakış ve daha fazla ayrıntı için bağlantılar için http://php.net/manual/en/array.sorting.php adresine bakın.

Nesne dizileri dahil çok boyutlu diziler

$array = array(
    array('foo' => 'bar', 'baz' => 42),
    array('foo' => ...,   'baz' => ...),
    ...
);

$arrayHer girişin 'foo' anahtarına göre sıralamak isterseniz , özel bir karşılaştırma işlevine ihtiyacınız vardır . Yukarıdaki sortve ilgili işlevler, karşılaştırmayı ve sıralamayı bildikleri basit değerler üzerinde çalışır. PHP gibi karmaşık bir değer ile ne yapacağını basitçe "bilmek" değildir array('foo' => 'bar', 'baz' => 42); bu yüzden söylemelisin.

Bunu yapmak için bir karşılaştırma işlevi oluşturmanız gerekir . Bu işlev iki öğe alır ve 0bu öğeler eşit kabul 0edilirse, ilk değerin daha düşük bir değerden 0ve ilk değerin daha yüksek bir değerden daha yüksek bir değerden dönmesi gerekir . Tek gereken bu:

function cmp(array $a, array $b) {
    if ($a['foo'] < $b['foo']) {
        return -1;
    } else if ($a['foo'] > $b['foo']) {
        return 1;
    } else {
        return 0;
    }
}

Genellikle, geri arama olarak anonim bir işlev kullanmak istersiniz . Bir yöntem veya statik yöntem kullanmak istiyorsanız , PHP'de geri arama belirtmenin diğer yollarına bakın .

Daha sonra şu işlevlerden birini kullanırsınız:

Yine, yalnızca anahtar / değer ilişkilendirmelerini tutma ve değerlere veya anahtarlara göre sıralama yapmalarına göre farklılık gösterirler. Ayrıntılar için belgelerini okuyun.

Örnek kullanım:

usort($array, 'cmp');

usortdiziden iki öğe alır ve cmpişlevinizi bunlarla çağırır . Yani cmp()birlikte adı verilecek $aşekilde array('foo' => 'bar', 'baz' => 42)ve $bbaşka şekilde array('foo' => ..., 'baz' => ...). İşlev daha sonra usortdeğerlerden hangisinin daha büyük olduğuna veya eşit olup olmadıklarına döner . usortiçin farklı değerler geçen bu işlemi tekrarlar $ave $bdizi kriteri kadar. cmpFonksiyonu, birçok kez adı verilecek en azından değerler olduğu gibi çok kez $arrayfarklı ait değerlerin kombinasyonları ile, $ave $bher zaman.

Bu fikre alışmak için şunu deneyin:

function cmp($a, $b) {
    echo 'cmp called with $a:', PHP_EOL;
    var_dump($a);
    echo 'and $b:', PHP_EOL;
    var_dump($b);
}

Tek yaptığınız, iki öğeyi karşılaştırmak için özel bir yol tanımlamaktı. Bu her türlü değerle çalışır.

Bu arada, bu herhangi bir değer üzerinde çalışır, değerlerin karmaşık diziler olması gerekmez. Yapmak istediğiniz özel bir karşılaştırmanız varsa, bunu basit bir sayı dizisinde de yapabilirsiniz.

sort referans ile sıralar ve yararlı bir şey döndürmez!

Dizinin yerinde sıralandığını, dönüş değerini hiçbir şeye atamanıza gerek olmadığını unutmayın. $array = sort($array)diziyi true, sıralı bir diziyle değil, ile değiştirir . Sadece sort($array);çalışıyor.

Özel sayısal karşılaştırmalar

bazSayısal tuşa göre sıralamak istiyorsanız , tek yapmanız gereken:

function cmp(array $a, array $b) {
    return $a['baz'] - $b['baz'];
}

Sayesinde matematik güç değeri <0, 0 veya> 0 olmasına bağlı olarak, bu döner $adaha düşüktür, veya daha büyük eşit $b.

Bunun floatdeğerlerde iyi sonuç vermeyeceğini unutmayın , çünkü bunlar bir değere indirilecek intve hassasiyeti kaybedecektir. Açık kullanın -1, 0ve 1bunun yerine değerleri döndürür.

Nesneler

Bir dizi nesneniz varsa, aynı şekilde çalışır:

function cmp($a, $b) {
    return $a->baz - $b->baz;
}

Fonksiyonlar

Arama işlevleri de dahil olmak üzere bir karşılaştırma işlevi içinde ihtiyacınız olan her şeyi yapabilirsiniz:

function cmp(array $a, array $b) {
    return someFunction($a['baz']) - someFunction($b['baz']);
}

Teller

İlk dize karşılaştırma sürümü için bir kısayol:

function cmp(array $a, array $b) {
    return strcmp($a['foo'], $b['foo']);
}

strcmptam olarak bekleneni vermez neyi cmpburada, döndürür -1, 0veya 1.

Uzay gemisi operatörü

PHP 7 , türler arasındaki karşılaştırmalardan eşit / daha küçük / daha büyük olanı birleştiren ve basitleştiren uzay gemisi operatörünü tanıttı :

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

Birden çok alana göre sıralama

Öncelikle sıralama yapmak istiyorsanız foo, ancak fooiki öğe için eşitse sıralama ölçütü baz:

function cmp(array $a, array $b) {
    if (($cmp = strcmp($a['foo'], $b['foo'])) !== 0) {
        return $cmp;
    } else {
        return $a['baz'] - $b['baz'];
    }
}

Tanıdık olanlar için, bu bir SQL sorgusuna eşdeğerdir ORDER BY foo, baz.
Ayrıca bu çok düzgün steno versiyonuna ve rastgele sayıda anahtar için böyle bir karşılaştırma fonksiyonunun nasıl oluşturulacağına bakın .

Manuel, statik bir sıraya göre sıralama

Elemanları "foo", "bar", "baz" gibi bir "manuel sipariş" olarak sıralamak istiyorsanız :

function cmp(array $a, array $b) {
    static $order = array('foo', 'bar', 'baz');
    return array_search($a['foo'], $order) - array_search($b['foo'], $order);
}

Yukarıdakilerin tümü için, PHP 5.3 veya üstünü kullanıyorsanız (ve gerçekten yapmalısınız), daha kısa kod için anonim işlevler kullanın ve etrafta başka bir küresel işlevin olmasını önlemek için:

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

Karmaşık çok boyutlu bir diziyi sıralamak bu kadar basit olabilir. Yine, sadece PHP'ye iki öğeden hangisinin "daha büyük" olduğunu söylemeyi öğretmeyi düşünün ; PHP gerçek sıralama yapalım.

Ayrıca, yukarıdakilerin tümü için, artan ve azalan düzen arasında geçiş yapmak için $ave $bargümanlarını değiştirin . Örneğin:

return $a['baz'] - $b['baz']; // ascending
return $b['baz'] - $a['baz']; // descending

Bir diziyi diğerine göre sıralama

Ve bir tuhaflık var array_multisort, bu da bir diziyi diğerine göre sıralamanızı sağlar:

$array1 = array( 4,   6,   1);
$array2 = array('a', 'b', 'c');

Burada beklenen sonuç:

$array2 = array('c', 'a', 'b');  // the sorted order of $array1

array_multisortOraya ulaşmak için kullanın :

array_multisort($array1, $array2);

PHP 5.5.0'dan array_columnitibaren bir sütunu çok boyutlu bir diziden ayıklamak ve diziyi bu sütundaki sıralamak için kullanabilirsiniz:

array_multisort(array_column($array, 'foo'), SORT_DESC, $array);

PHP 7.0.0'dan itibaren, bir nesne dizisinden özellikleri ayıklayabilirsiniz.


Daha sık karşılaşılan vakalarınız varsa, bu yanıtı düzenlemekten çekinmeyin.


Sayısal karşılaştırma işlevi kayan değerlerde çalışmaz; Ne demek istediğimi bildiğine eminim :)
Ja͢ck

1
Statik düzen array_flip()için, örneğin $order[$a['foo']]yerine , daha hızlı konum aramasını kullanmak için başvurdum array_search($a['foo'], $order).
Ja͢ck

Biraz büyük bir düzenleme olabilir: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b ama bir gelişme olduğunu düşünüyorsanız ve gerekli her şeyi dahil edersem uygulayabilirim.
Rizier123

@ Rizier123 Bu çabayı alkışlıyorum, çok iyi bir yazı; ama çok benzer olsa bile, ayrı bir cevap olarak gönderirseniz tercih ederim. Yeniden yazmanız çok fazla ayrıntı içeriyor (referansa göre geçiş, büyük tablo vb.), Ancak bu ayrıntı karşılaştırma işlevinin IMHO'nun çalışmalarının ana konusuna düzgün bir şekilde girmekten uzaklaşıyor. El kitabına açıkça birkaç kez atıfta bulunuyorum, çünkü bu tür detaylara bakılması gerekiyor; burada tekrarlamaya ve aktarmaya çalıştığım ana fikrin dikkatini dağıtmaya gerek yok.
deceze

@deceze Ana soru, referans bir Soru ve Cevap olduğu için, bilgileri olabildiğince kompakt ve okunabilir göstermek ve kullanıcıların sıralama işlevlerini bulmalarını kolaylaştırmaktır. Bir kaç şey tweaked: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b ayrı cevap olarak göndermeye yararlı ve değerli ise çok benzer içerik olduğundan ama hala bu konuda düşünmek zorunda
Rizier123

139

Pek çok temel yöntem zaten deceze ile kaplıdır Diğer türlere bakmaya çalışacağım

SPL ile sıralama

SplHeap

class SimpleHeapSort extends SplHeap {
    public function compare($a, $b) {
        return strcmp($a, $b);
    }
}

// Let's populate our heap here (data of 2009)
$heap = new SimpleHeapSort();
$heap->insert("a");
$heap->insert("b");
$heap->insert("c");

echo implode(PHP_EOL, iterator_to_array($heap));

Çıktı

c
b
a

SplMaxHeap

SplMaxHeap sınıfı, bir yığının ana işlevlerini sağlar ve üst sınırı en üstte tutar.

$heap = new SplMaxHeap();
$heap->insert(1);
$heap->insert(2);
$heap->insert(3);

SplMinHeap

SplMinHeap sınıfı, bir yığının ana işlevlerini sağlar ve minimumları en üstte tutar.

$heap = new SplMinHeap ();
$heap->insert(3);
$heap->insert(1);
$heap->insert(2);

Diğer Sıralama Türleri

Kabarcık Sırala

Gönderen kabarcık sıralama Vikipedi'ye:

Kabarcık sıralama, bazen yanlış batırma olarak adlandırılır, sıralanacak listeye art arda adım atarak, bitişik öğelerin her bir çiftini karşılaştırarak ve yanlış sırada olmaları durumunda değiştiren basit bir sıralama algoritmasıdır. Listeden geçiş, değiştirmenin gerekmediği kadar tekrarlanır, bu da listenin sıralandığını gösterir. Algoritma, adını daha küçük öğelerin "kabarma" biçiminden listenin en üstüne götürür. Yalnızca öğeler üzerinde işlem yapmak için karşılaştırmalar kullandığından bir karşılaştırma türüdür. Algoritma basit olmasına rağmen, diğer sıralama algoritmalarının çoğu büyük listeler için daha verimlidir.

function bubbleSort(array $array) {
    $array_size = count($array);
    for($i = 0; $i < $array_size; $i ++) {
        for($j = 0; $j < $array_size; $j ++) {
            if ($array[$i] < $array[$j]) {
                $tem = $array[$i];
                $array[$i] = $array[$j];
                $array[$j] = $tem;
            }
        }
    }
    return $array;
}

Seçim sıralaması

Gönderen seçerek sıralama Vikipedi'ye:

Bilgisayar biliminde, seçim sıralama bir sıralama algoritmasıdır, özellikle yerinde bir karşılaştırma sıralamadır. O (n2) zaman karmaşıklığına sahiptir, bu da büyük listelerde verimsiz olmasını sağlar ve genellikle benzer ekleme türünden daha kötü performans gösterir. Seçim sıralaması basitliği nedeniyle not edilir ve özellikle yardımcı belleğin sınırlı olduğu bazı durumlarda daha karmaşık algoritmalara göre performans avantajlarına sahiptir.

function selectionSort(array $array) {
    $length = count($array);
    for($i = 0; $i < $length; $i ++) {
        $min = $i;
        for($j = $i + 1; $j < $length; $j ++) {
            if ($array[$j] < $array[$min]) {
                $min = $j;
            }
        }
        $tmp = $array[$min];
        $array[$min] = $array[$i];
        $array[$i] = $tmp;
    }
    return $array;
}

Ekleme sıralaması

Ekleme türüyle ilgili Wikipedia makalesinden:

Ekleme sıralaması, son sıralanmış diziyi (veya listeyi) bir kerede bir öğe oluşturan basit bir sıralama algoritmasıdır. Büyük listelerde hızlı sıralama, yığın veya birleştirme sıralaması gibi daha gelişmiş algoritmalardan çok daha az verimlidir. Ancak, ekleme sıralaması çeşitli avantajlar sağlar:

function insertionSort(array $array) {
    $count = count($array);
    for($i = 1; $i < $count; $i ++) {

        $j = $i - 1;
        // second element of the array
        $element = $array[$i];
        while ( $j >= 0 && $array[$j] > $element ) {
            $array[$j + 1] = $array[$j];
            $array[$j] = $element;
            $j = $j - 1;
        }
    }
    return $array;
}

ShellSort

Gönderen ShellSort Vikipedi'ye:

Shell sıralama veya Shell yöntemi olarak da bilinen Shellsort, yerinde bir karşılaştırma sıralamasıdır. Komşu elemanlarla bitirmeden önce öğelerin karşılaştırılması ve birbirinden uzak elemanlarla değişimine başlayarak, ekleme veya kabarcık sıralama gibi bir takas türünü genelleştirir.

function shellSort(array $array) {
    $gaps = array(
            1,
            2,
            3,
            4,
            6
    );
    $gap = array_pop($gaps);
    $length = count($array);
    while ( $gap > 0 ) {
        for($i = $gap; $i < $length; $i ++) {
            $tmp = $array[$i];
            $j = $i;
            while ( $j >= $gap && $array[$j - $gap] > $tmp ) {
                $array[$j] = $array[$j - $gap];
                $j -= $gap;
            }
            $array[$j] = $tmp;
        }
        $gap = array_pop($gaps);
    }
    return $array;
}

Tarak sıralaması

Gönderen Tarak tür Vikipedi'ye:

Tarak sıralama, 1980'de Wlodzimierz Dobosiewicz tarafından tasarlanan nispeten basit bir sıralama algoritmasıdır. Daha sonra 1991 yılında Stephen Lacey ve Richard Box tarafından yeniden keşfedildi. Tarak sıralaması kabarcık türünde gelişir.

function combSort(array $array) {
    $gap = count($array);
    $swap = true;
    while ( $gap > 1 || $swap ) {
        if ($gap > 1)
            $gap /= 1.25;
        $swap = false;
        $i = 0;
        while ( $i + $gap < count($array) ) {
            if ($array[$i] > $array[$i + $gap]) {
                // swapping the elements.
                list($array[$i], $array[$i + $gap]) = array(
                        $array[$i + $gap],
                        $array[$i]
                );
                $swap = true;
            }
            $i ++;
        }
    }
    return $array;
}

Sıralamayı birleştir

Gönderen Birleştirme tür Vikipedi'ye:

Bilgisayar biliminde, bir birleştirme sıralaması (ayrıca yaygın olarak yazılan birleştirme sıralaması), O (n log n) karşılaştırma tabanlı bir sıralama algoritmasıdır. Çoğu uygulama kararlı bir sıralama üretir; bu, uygulamanın sıralanmış çıktıdaki eşit öğelerin giriş sırasını koruduğu anlamına gelir

function mergeSort(array $array) {
    if (count($array) <= 1)
        return $array;

    $left = mergeSort(array_splice($array, floor(count($array) / 2)));
    $right = mergeSort($array);

    $result = array();

    while ( count($left) > 0 && count($right) > 0 ) {
        if ($left[0] <= $right[0]) {
            array_push($result, array_shift($left));
        } else {
            array_push($result, array_shift($right));
        }
    }
    while ( count($left) > 0 )
        array_push($result, array_shift($left));

    while ( count($right) > 0 )
        array_push($result, array_shift($right));

    return $result;
}

Hızlı sıralama

Gönderen Quicksort Vikipedi'ye:

Quicksort veya bölüm değiştirme sıralaması, Tony Hoare tarafından geliştirilen ve ortalama olarak n öğelerini sıralamak için O (n log n) karşılaştırmaları yapan bir sıralama algoritmasıdır. En kötü durumda, bu davranış nadir olmakla birlikte O (n2) karşılaştırmaları yapar.

function quickSort(array $array) {
    if (count($array) == 0) {
        return $array;
    }
    $pivot = $array[0];
    $left = $right = array();
    for($i = 1; $i < count($array); $i ++) {
        if ($array[$i] < $pivot) {
            $left[] = $array[$i];
        } else {
            $right[] = $array[$i];
        }
    }
    return array_merge(quickSort($left), array(
            $pivot
    ), quickSort($right));
}

Permütasyon sıralaması

Gönderen Permütasyon tür Vikipedi'ye:

Sıralı olanı bulana kadar giriş dizisinin / listenin olası permütasyonlarını oluşturarak devam eden permütasyon sıralaması.

function permutationSort($items, $perms = array()) {
    if (empty($items)) {
        if (inOrder($perms)) {
            return $perms;
        }
    } else {
        for($i = count($items) - 1; $i >= 0; -- $i) {
            $newitems = $items;
            $newperms = $perms;
            list($foo) = array_splice($newitems, $i, 1);
            array_unshift($newperms, $foo);
            $res = permutationSort($newitems, $newperms);
            if ($res) {
                return $res;
            }
        }
    }
}

function inOrder($array) {
    for($i = 0; $i < count($array); $i ++) {
        if (isset($array[$i + 1])) {
            if ($array[$i] > $array[$i + 1]) {
                return False;
            }
        }
    }
    return True;
}

Radix sıralaması

Gönderen Radix tür Vikipedi'ye:

Bilgisayar biliminde, sayı tabanı sıralaması, anahtarları aynı anlamlı konumu ve değeri paylaşan ayrı basamaklara göre gruplandırarak tamsayı anahtarlarıyla verileri sıralayan karşılaştırmalı olmayan bir tamsayı sıralama algoritmasıdır.

// Radix Sort for 0 to 256
function radixSort($array) {
    $n = count($array);
    $partition = array();

    for($slot = 0; $slot < 256; ++ $slot) {
        $partition[] = array();
    }

    for($i = 0; $i < $n; ++ $i) {
        $partition[$array[$i]->age & 0xFF][] = &$array[$i];
    }

    $i = 0;

    for($slot = 0; $slot < 256; ++ $slot) {
        for($j = 0, $n = count($partition[$slot]); $j < $n; ++ $j) {
            $array[$i ++] = &$partition[$slot][$j];
        }
    }
    return $array;
}

4
@deceze tüm temelleri örtülü .. Ben alakalı olmak için başka bir yol aramak zorunda kaldım :)
Baba

5
Daha akademik sıralama yöntemleri ile yanlış bir şey görmüyorum :) çoğu uygulama için çok daha az kullanışlı ama bazen istenebilir / gerekli olabilir, özellikle zaman içinde bunların çoğunu unuttuğumdan beri referans olması yararlıdır
Dave

Aslında, hızlı sıralama için pivotun üç değerin ortanca olarak seçilmesi önerilir : ilk, orta ve son elemanlar . Bu , pivot seçimine örnek. Bu, en kötü durum tersine sıralanmış diziden kaçınmaya izin verir ( O(n^2)yalnızca ilk öğeyi pivot olarak kullanırsak karşılaştırmalara neden olur )
Alma Do

Ben spl normal dizi sıralama daha hızlı çalıştığını duydum.
jewelhuq

Bugünlerde Dave ile aynı fikirdeyim neredeyse nadiren hatırlıyorum ya da kullanıyorum.
Mike Nguyen

43

Kararlı sıralama

Diyelim ki böyle bir diziniz var:

['Kale', 'Kaleidoscope', 'Aardvark', 'Apple', 'Leicester', 'Lovely']

Ve şimdi sadece ilk harfi sıralamak istiyorsunuz:

usort($array, function($a, $b) {
    return strcmp($a[0], $b[0]);
});

Sonuç şudur:

['Apple', 'Aardvark', 'Kale', 'Kaleidoscope', 'Lovely', 'Leicester']

Sıralama sabit değildi!

İstekli gözlemci, dizi sıralama algoritmasının (QuickSort) kararlı bir sonuç üretmediğini ve aynı ilk harfin sözcükleri arasındaki orijinal düzenin korunmadığını fark etmiş olabilir. Bu durum önemsizdir ve tüm dizeyi karşılaştırmış olmalıyız, ancak diyelim ki kullanım durumunuz, birbirinin işini iptal etmemesi gereken farklı alanlarda birbirini takip eden iki tür gibi daha karmaşık.

Schwartz dönüşüm

Decorate-sort-undecorate deyim olarak da adlandırılan Schwartz dönüşümü , doğal olarak kararsız bir sıralama algoritması ile kararlı bir sıralama etkiler.

İlk olarak, her dizi öğesini birincil anahtar (değer) ve ikincil anahtar (dizini veya konumu) içeren başka bir diziyle süslersiniz:

array_walk($array, function(&$element, $index) {
    $element = array($element, $index); // decorate
});

Bu, diziyi buna dönüştürür:

[
    ['Kale', 0], ['Kaleidoscope', 1], 
    ['Aardvark', 2], ['Apple', 3], 
    ['Leicester', 4], ['Lovely', 5]
]

Şimdi karşılaştırma adımını ayarlıyoruz; ilk harfi tekrar karşılaştırırız, ancak aynıysa, ikincil anahtar orijinal sıralamayı korumak için kullanılır:

usort($array, function($a, $b) {
    // $a[0] and $b[0] contain the primary sort key
    // $a[1] and $b[1] contain the secondary sort key
    $tmp = strcmp($a[0][0], $b[0][0]);

    if ($tmp != 0) {
        return $tmp; // use primary key comparison results
    }

    return $a[1] - $b[1]; // use secondary key
});

Daha sonra, dekore ediyoruz:

array_walk($array, function(&$element) {
    $element = $element[0];
});

Nihai sonuç:

['Aardvark', 'Apple', 'Kale', 'Kaleidoscope', 'Leicester', 'Lovely']

Yeniden kullanım ne olacak?

Dönüştürülen dizi öğeleriyle çalışmak için karşılaştırma işlevinizi yeniden yazmanız gerekiyordu; hassas karşılaştırma işlevlerinizi düzenlemek istemeyebilirsiniz, bu nedenle karşılaştırma işlevi için bir sarıcı:

function stablecmp($fn)
{
    return function($a, $b) use ($fn) {
        if (($tmp = call_user_func($fn, $a[0], $b[0])) != 0) {
            return $tmp;
        } else {
            return $a[1] - $b[1];
        }
    };
}

Bu işlevi kullanarak sıralama adımını yazalım:

usort($array, stablecmp(function($a, $b) {
    return strcmp($a[0], $b[0]);
}));

İşte bu kadar! Bozulmamış karşılaştırma kodunuz geri döndü.


"Doğası gereği dengesiz bir sıralama algoritmasıyla istikrarlı bir sıralama yaratır" ifadeniz benim için ah-ha anıydı. Vikipedi sayfasında kararlı kelimeden bahsedilmiyor, ki bu bana dönüşümün güzelliği gibi geliyor. Utanç.
Tyler Collier

1
@TylerCollier Evet, bu Wikipedia referansının satırları arasında okumalısınız ... Size bunu yapma zahmetinden kurtardım ;-)
Ja͢ck

15

PHP 5.3'ten itibaren kapaklarla, sıralamanızı belirlemek için bir kapak kullanmak da mümkündür.

Örneğin, $ dizisinin month özelliği içeren bir nesne dizisi olduğunu varsayalım.

 $orderArray = array("Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec");

 usort($array, function($a, $b) use ($orderArray){
       return array_search($a->month, $orderArray) - array_search($b->month, $orderArray);
 }); 

Bunun, önceki göreli siparişleri kaldıracağını unutmayın (örneğin, önceden sıralanmış listedeki ilk "Temmuz" nesnesi, sıralamadan sonra Temmuz nesne grubunun sonunda olabilir). Bkz. Yukarıdaki "Kararlı Sıralama".
George Langley

9

LINQ

.NET'te LINQ, sıralama için, özellikle nesnelerin birden çok alana göre sıralanması gerektiğinde, karşılaştırma işlevleri üzerinde çok daha iyi bir sözdizimi sağlayan sıkça kullanılır. YaLinqo kütüphanesi * dahil olmak üzere birçok LINQ - PHP portu vardır . Bununla birlikte, diziler karmaşık karşılaştırma işlevleri yazmadan tek bir satırla sıralanabilir.

$sortedByName         = from($objects)->orderBy('$v->name');
$sortedByCount        = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');

Karşılaştırmalar, ikinci bir argüman olarak geri çağrı iletilerek daha da özelleştirilebilir, örneğin:

$sortedByFilenameNat  = from($objects)->orderBy('$v->filename', 'strnatcmp');

Burada, '$v->count'bir kısayol function ($v) { return $v->count; }(her ikisi de kullanılabilir). Bu yöntem zincirleri yineleyicileri döndürür, yineleyiciler ->toArray()gerekirse sonuna ekleyerek dizilere dönüştürülebilir .

Dahili olarak, orderByve benzer yöntemler (uygun dizi sıralama arama işlevleri uasort, krsort, multisort, usortvb.)

LINQ, SQL'den esinlenen daha birçok yöntem içerir: filtreleme, gruplama, birleştirme, toplama vb. Diziler ve nesneler üzerinde karmaşık dönüşümlerin veritabanlarına dayanmadan gerçekleştirilmesi gereken durumlar için en uygun yöntemdir.

* benim tarafımdan geliştirildi, daha fazla ayrıntı ve diğer LINQ bağlantı noktaları ile karşılaştırma için benioku dosyasına bakın


3

Anahtar değere göre çok boyutlu sıralama

Anahtar değere göre çok boyutlu bir dizinin doğal çeşidi ve ayrıca orijinal düzeni koru (ana anahtarları karıştırmayın):

function multisortByKeyValue( $k, $arr ) {
    $ids   = array();
    $index = 1;

    foreach ( $arr as $key => $row ) {
        $ids[ $key ] = intval( $row[ $k ] ) . '-' . $index . '-' . $key;
        $index ++;
    }

    natsort( $ids );

    $arr = array_merge( $ids, $arr );

    return $arr;
}

Test durumu:

$arr = array(
    'id1' => array(
        'label'    => 'ID 1',
        'priority' => 30,
    ),
    'id2' => array(
        'label'    => 'ID 2',
        'priority' => 70,
    ),
    'id3' => array(
        'label'    => 'ID 3',
        'priority' => 20,
    ),
    'id4' => array(
        'label'    => 'ID 4',
        'priority' => 30,
    ),
);

$sorted = multisortByKeyValue( 'priority', $arr );

// $sorted equals to:
/*
array (
  'id3' => array (
    'label' => 'ID 3',
    'priority' => 20,
  ),
  'id1' => array (
    'label' => 'ID 1',
    'priority' => 30,
  ),
  'id4' => array (
    'label' => 'ID 4',
    'priority' => 30,
  ),
  'id2' => array (
    'label' => 'ID 2',
    'priority' => 70,
  ),
)
*/

2

Nspl'den sıralanan işlevle dizileri sıralamak çok uygundur :

Temel sıralama

// Sort array
$sorted = sorted([3, 1, 2]);

// Sort array in descending order
$sortedDesc = sorted([3, 1, 2], true);

İşlev sonucuna göre sıralama

// Sort array by the result of a given function (order words by length)
$sortedByLength = sorted(['bc', 'a', 'abc'], 'strlen');
$sortedByLengthDesc = sorted(['bc', 'a', 'abc'], true, 'strlen');

// Sort array by the result of user-defined function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], function($v) { return $v[0]; }); 

// Which is the same as
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], itemGetter(0));
$sortedByTheFirstCharacterDesc = sorted(['bc', 'a', 'abc'], true, itemGetter(0));

// itemGetter(0) returns a function which takes an argument with access by index/key
// and returns the value at index 0

Çok boyutlu diziyi sıralama

// Sort multidimensional array (sort list of users by their names)
$users = [
    array('name' => 'Robert', 'age' => 20),
    array('name' => 'Alex', 'age' => 30),
    array('name' => 'Jack', 'age' => 25),
];
$sortedByName = sorted($users, itemGetter('name'));
$sortedByNameDesc = sorted($users, true, itemGetter('name'));

// itemGetter('name') returns a function which takes an argument with access by index/key
// and returns the value of the 'name' key

Nesne dizisini sıralama

// Lets assume we have class User(name, age) with properties name and age
// and public methods getName() and getAge()
$users = [
    new User('Robert', 20),
    new User('Alex', 30),
    new User('Jack', 25),
];

// Sort list of objects by property value (sort list of users by their name)
$sortedByName = sorted($users, propertyGetter('name'));
$sortedByNameDesc = sorted($users, true, propertyGetter('name'));

// propertyGetter('name') returns a function which takes an object
// and returns the value of its 'name' property

// Sort list of objects by method result (sort list of users by their age)
$sortedByAge = sorted($users, methodCaller('getAge'));
$sortedByAgeDesc = sorted($users, true, methodCaller('getAge'));

// methodCaller('getAge') returns a function which takes an object
// and returns the result of its getAge() method

Karşılaştırma işleviyle sıralama

// Sort with a comparison function (order words lexicographically with strcmp)
$sortedLexicographically = sorted(['bc', 'a', 'abc'], false, null, 'strcmp');

// Sort with user-defined comparison function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], false, null, function($v1, $v2) {
    return chr($v1[0]) - chr($v2[0]);
});

Tüm bu örnekleri burada görebilirsiniz .


2

Anahtar değerine göre sipariş vermek istiyorsanız, o zaman bir satır, zarif ve net yapabilirsiniz. Bu artan fiyata göre sipariş verecektir. Array_multisort ve array_column kullanır.

   Array([0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => coffee [price] => 9.99 ) [2] => Array ( [name] => rice [price] => 4.04 ) )

   array_multisort (array_column($array, 'price'), SORT_ASC, $array);

üretmek için

     Array ( [0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => rice [price] => 4.04 ) [2] => Array ( [name] => coffee [price] => 9.99 ) )

1

Bu sayfa çok kapsamlı, ancak PHP7 + 'nın güzel bir çocuğu olan uzay gemisi operatörünün (üç yönlü karşılaştırma operatörü) müthiş faydası hakkında biraz daha eklemek istiyorum.

Birden çok sıralama koşulu uygulamak için uzay gemisi operatörünü kullanma

Bu, kod şişkinliğini azaltma ve okunabilirliği artırmada büyük adımlar atıyor.

Birden çok koşulu işlemek için özel sıralama ( usort()/ uasort()/ uksort()) işlevinizi yazarken, yalnızca operatörün her iki tarafına dengeli diziler yazmanız ve sonucu döndürmeniz gerekir. Yuvalanmış koşul bloğu veya birden fazla dönüş yok.

Operatörün her iki tarafındaki elemanlar, her seferinde bir tane olmak üzere soldan sağa hareket ettirilecek ve bağlantısız karşılaşıldığında veya elemanlar karşılaştırıldığında değerlendirmeyi geri döndürecektir.

Gösterilerim için örnek veriler:

$multidimArray = [
    'a' => [
        'boolean' => true,
        'natString' => 'text10',
        'object' => (object)['prop' => 2],
        'float' => -.5,
        'mixed' => []
    ],
    'b' => [
        'boolean' => true,
        'natString' => 'text12',
        'object' => (object)['prop' => 4],
        'float' => 0,
        'mixed' => null
    ],
    'c' => [
        'boolean' => false,
        'natString' => 'text100',
        'object' => (object)['prop' => 9],
        'float' => -.5,
        'mixed' => false
    ],
    'd' => [
        'boolean' => true,
        'natString' => 'text1',
        'object' => (object)['prop' => 9],
        'float' => -5,
        'mixed' => "\0"
    ],
    'e' => [
        'boolean' => false,
        'natString' => 'text2',
        'object' => (object)['prop' => 2],
        'float' => .5,
        'mixed' => ''
    ]
];

Gösterimler (Stackoverflow sayfa şişmesini önlemek için lütfen çıktılar için demo bağlantısına bakın ):

  • Sıralama mantığı:

    1. boolean DESC (yanlış = 0, doğru = 1, bu yüzden yanlışlardan önce doğrular)
    2. şamandıra ASC

      uasort($multidimArray, function($a, $b) {
          return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']];
      });
  • Sıralama mantığı:

    1. karışık ASC
    2. nesne ASC
    3. boolean ASC

      uasort($multidimArray, function($a, $b) {
          return [$a['mixed'], $a['object']->prop, $a['boolean']] <=> [$b['mixed'], $b['object']->prop, $b['boolean']];
      });
  • Sıralama mantığı:

    1. nesne ASC özellik sayısı
    2. karışık DESC tekrarlanabilirliği
    3. natString uzunluğu ASC
    4. natString ASC

      uasort($multidimArray, function($a, $b) {
          return [count(get_object_vars($a['object'])), is_iterable($a['mixed']), strlen($a['natString']), $a['natString']]
                 <=>
                 [count(get_object_vars($b['object'])), is_iterable($b['mixed']), strlen($b['natString']), $b['natString']];
      });

Bu sözdizimi, değerleri, işlevsel sonuçları, derin iç içe verileri ve sıralama yönünü zarif bir şekilde sıralamanızı sağlar. Bu kesinlikle php araç kemeri koyarak değer ... veritabanı olmayan verileri işlediğiniz durumlarda - tabii ki SQL çok daha mantıklı bir teknik olacaktır çünkü.

Kendi takdirinize bağlı olarak, PHP7.4'ten bu anonim işlevlerle ok sözdizimini kullanabilirsiniz. Ok sözdizimi ile aynı komut dosyası .


0

Birisi dizileri işlemek için daha basit bir çözüm istiyorsa, sadece tuşlara göre sıralamanızı sağlayan bir sortBy işlevine sahip Laravel Collection paketini kullanın.

$collection->sortBy('forename')->sortBy('surname');

yani, önce a, sonra b, sonra c'ye göre sıralamak için doğru fıkra

sortBy('c')->sortBy('b')->sortBy('a')

https://packagist.org/packages/tightenco/collect


-1

Bir diziyi sıralamanın birkaç yolu vardır. Tüm bu task.fist'i yapmak için bazı yöntemlerden bahsedeceğim, '$ numbers' olarak adlandırılan bir tamsayı dizisi vereceğim.

$number = array(8,9,3,4,0,1,2);

Dizi oluşturmanın normal yolu budur. Diyelim ki bu diziyi artan sırada sıralamak istiyorum. Bunun için 'sort ()' yöntemi kullanılabilir.

<?php

    $number = array(8,9,3,4,0,1,2);
    sort($number);

   foreach ($number as $value) {
       echo $value."  ";
   }
?>

Şimdi bunun çıktısını düşünün,

resim açıklamasını buraya girin

Yazdırılan sayı dizisinin sıralandığını görebilirsiniz. Bu sayı dizisinin sıralanmasının azalan sırada olmasını istiyorsanız, o görev için 'rsort ()' yöntemi kullanılabilir.

<?php

     $number = array(8,9,3,4,0,1,2);
     rsort($number);

     foreach ($number as $value) {
        echo $value."  ";
     }
?>

çıktı düşünün ..

resim açıklamasını buraya girin

Şimdi dizi azalan düzende sıralanır.Tamam, ilişkilendirilebilir bir dizi düşünelim. İlişkilendirilebilir bir dizi vereceğim (İlişkilendirilebilir dizi şu anlama gelir, Her dizini benzersiz anahtar değerine sahip bir dizi.),

$number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);

Yani, Şimdi bu diziyi kendi değerlerine göre artan düzende sıralamak istiyorum. '' () 'Yöntemi bunun için kullanılabilir.

<?php

   $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
   asort($number);

   foreach ($number as $value) {
      echo $value."  ";
    }
?>

Azalan düzeni değerlerine göre sıralıyorsanız, 'arsort ()' yöntemi kullanılabilir. Bu diziyi anahtar değerine göre sıralamak istediğinizi varsayalım. Bunda 'ksort ()' yöntemi kullanılabilir.

<?php

     $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
     ksort($number);

     foreach ($number as $value) {
         echo $value."  ";
     }
?>

Şimdi çıktıyı düşünün. resim açıklamasını buraya girin

Şimdi dizi, anahtar değerine göre sıralanır. Diziyi anahtar değerine göre azalan sırada sıralamak isterseniz, 'krsort ()' yöntemi kullanılabilir.

<?php

    $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
    krsort($number);

    foreach ($number as $value) {
       echo $value."  ";
    }
?>

Şimdi ilişkilendirilebilir dizi, anahtar değerlerine göre azalan düzende sıralanır. Çıktıya bakın. resim açıklamasını buraya girin

Bunlar php artan veya azalan bir dizi sıralamak için bazı yöntemler vardır. Umarım bir fikir olabilir. Teşekkür ederim!


Deceze zaten bu anlayışları kapsamaz: "Bunlar arasındaki fark, yalnızca anahtar / değer ilişkilerinin tutulması (" a "fonksiyonları), düşük-yüksekten veya ters (" r ") şeklinde sıralanması, değerleri veya anahtarları ("k") ve değerleri nasıl karşılaştırdığını sıralar ("nat" ile normal). " kabul edilen cevapta?
mickmackusa

-2

En basit olanı, herhangi bir döngü olmadan diziyi sıralamak için usort işlevini kullanmaktır: Aşağıda bir örnek vardır:

   $array_compare= array("0" =>4,"1"=>2,"2"=>500,"3"=>100);

Bu, aşağıdaki sıraya göre sıralanır:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) > 0 ? 1 :-1;
    });

Bu, artan sıraya göre sıralanır:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) < 0 ? 1 :-1;
    });

1
1) Örnek ve kod tutarsız. 2) Bu, yukarıdaki cevaplarda çok ayrıntılı bir şekilde açıklanmıştır. 3) Muhtemelen farklı bir soruya cevap vermeye mi çalışıyorsunuz?
deceze
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.