Làm thế nào tôi có thể sắp xếp các mảng và dữ liệu trong PHP?


292

Câu hỏi này nhằm mục đích tham khảo cho các câu hỏi về sắp xếp mảng trong PHP. Thật dễ dàng để nghĩ rằng trường hợp cụ thể của bạn là duy nhất và xứng đáng với một câu hỏi mới, nhưng hầu hết thực sự là các biến thể nhỏ của một trong những giải pháp trên trang này.

Nếu câu hỏi của bạn được đóng lại như một bản sao của câu hỏi này, vui lòng yêu cầu mở lại câu hỏi của bạn nếu bạn có thể giải thích tại sao nó khác biệt rõ rệt với tất cả những điều dưới đây.

Làm cách nào để sắp xếp một mảng trong PHP?
Làm cách nào để sắp xếp một mảng phức tạp trong PHP?
Làm cách nào để sắp xếp một mảng các đối tượng trong PHP?


  1. Mảng một chiều cơ bản; Bao gồm Mảng nhiều chiều, incl. mảng của các đối tượng; Bao gồm Sắp xếp một mảng dựa trên mảng khác

  2. Sắp xếp với SPL

  3. Sắp xếp ổn định

Để biết câu trả lời thực tế sử dụng các hàm hiện có của PHP, hãy xem 1., để biết câu trả lời chi tiết mang tính hàn lâm về các thuật toán sắp xếp (mà các hàm của PHP thực hiện và bạn có thể cần những trường hợp thực sự rất phức tạp), xem 2.


@jterry Chính xác, đó là lý do tại sao tôi thực hiện điều này để cuối cùng có một câu hỏi tham khảo tốt để chống lại. Trả lời từng bông tuyết độc đáo không giúp được ai. :)
lừa dối

3
Tôi nghĩ mọi người chỉ nên xem php.net
Alexander Jardim

@Alex Hà! Chắc chắn rồi. Vấn đề là: không ai RTFM. : D
lừa dối

2
Chúng tôi đã có sẵn những câu trả lời đó, tôi đề nghị bạn liệt kê liên kết các câu trả lời tốt nhất bên trong mỗi câu trả lời ở đây thay vì sao chép (hoặc viết lại) nội dung. Ngoài ra các mảng có xu hướng được nhìn thấy riêng lẻ, vì vậy công việc vẫn còn để bỏ phiếu chống lại các bản sao trong mọi trường hợp.
hakre

1
@deceze: Nếu không có ai RTFM, thì cũng không ai sẽ RTFQA - Câu hỏi và trả lời hiện tại :)
hakre

Câu trả lời:


164

Mảng một chiều cơ bản

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

Các hàm sắp xếp áp dụng:

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

Sự khác biệt giữa chúng chỉ đơn thuần là liệu các liên kết giá trị khóa được giữ (các ahàm ""), cho dù nó sắp xếp từ thấp đến cao hoặc đảo ngược (" r"), cho dù nó sắp xếp các giá trị hoặc khóa (" k") và cách so sánh các giá trị (" nat" so với bình thường). Xem http://php.net/manual/en/array.sorting.php để biết tổng quan và liên kết đến các chi tiết khác.

Mảng đa chiều, bao gồm cả mảng của các đối tượng

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

Nếu bạn muốn sắp xếp $arraytheo khóa 'foo' của mỗi mục, bạn cần có chức năng so sánh tùy chỉnh . Các hàm trên sortvà các hàm liên quan hoạt động trên các giá trị đơn giản mà chúng biết cách so sánh và sắp xếp. PHP không chỉ đơn giản là "biết" phải làm gì với một giá trị phức tạp như thế array('foo' => 'bar', 'baz' => 42); Vì vậy, bạn cần phải nói với nó.

Để làm điều đó, bạn cần tạo một chức năng so sánh . Hàm đó có hai phần tử và phải trả về 0nếu các phần tử này được coi là bằng nhau, giá trị thấp hơn 0nếu giá trị đầu tiên thấp hơn và giá trị cao hơn 0nếu giá trị đầu tiên cao hơn. Đó là tất cả những gì cần thiết:

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

Thông thường, bạn sẽ muốn sử dụng một chức năng ẩn danh làm cuộc gọi lại. Nếu bạn muốn sử dụng một phương thức hoặc phương thức tĩnh, hãy xem các cách khác để chỉ định một cuộc gọi lại trong PHP .

Sau đó, bạn sử dụng một trong các chức năng sau:

Một lần nữa, chúng chỉ khác nhau ở chỗ chúng giữ các liên kết khóa-giá trị và sắp xếp theo giá trị hoặc khóa. Đọc tài liệu của họ để biết chi tiết.

Ví dụ sử dụng:

usort($array, 'cmp');

usortsẽ lấy hai mục từ mảng và gọi cmphàm của bạn với chúng. Vì vậy, cmp()sẽ được gọi với $atheo array('foo' => 'bar', 'baz' => 42)$bnhư nhau array('foo' => ..., 'baz' => ...). Hàm sau đó trả về usortgiá trị nào lớn hơn hoặc chúng có bằng nhau không. usortlặp lại quá trình này thông qua các giá trị khác nhau cho $a$bcho đến khi mảng được sắp xếp. Các cmpchức năng sẽ được gọi nhiều lần, ít nhất là nhiều lần như có giá trị trong $array, với sự kết hợp khác nhau của các giá trị cho $a$bmỗi lần.

Để làm quen với ý tưởng này, hãy thử điều này:

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

Tất cả những gì bạn đã làm là xác định một cách tùy chỉnh để so sánh hai mục, đó là tất cả những gì bạn cần. Điều đó làm việc với tất cả các loại giá trị.

Nhân tiện, điều này hoạt động trên bất kỳ giá trị nào, các giá trị không phải là mảng phức tạp. Nếu bạn có một so sánh tùy chỉnh bạn muốn làm, bạn cũng có thể làm điều đó trên một mảng số đơn giản.

sort sắp xếp theo tham chiếu và không trả lại bất cứ điều gì hữu ích!

Lưu ý rằng các mảng sắp xếp tại chỗ , bạn không cần gán giá trị trả về cho bất cứ điều gì. $array = sort($array)sẽ thay thế mảng bằng true, không phải bằng một mảng được sắp xếp. Chỉ cần sort($array);làm việc.

So sánh số tùy chỉnh

Nếu bạn muốn sắp xếp theo bazkhóa, đó là số, tất cả những gì bạn cần làm là:

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

Nhờ vào PoCHr oF MATH, điều này trả về giá trị <0, 0 hoặc> 0 tùy thuộc vào việc $acó thấp hơn, bằng hoặc lớn hơn $b.

Lưu ý rằng điều này sẽ không hoạt động tốt cho floatcác giá trị, vì chúng sẽ bị giảm xuống intvà mất độ chính xác. Sử dụng rõ ràng -1, 01trả về giá trị thay thế.

Các đối tượng

Nếu bạn có một mảng các đối tượng, nó hoạt động theo cùng một cách:

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

Chức năng

Bạn có thể làm bất cứ điều gì bạn cần trong một chức năng so sánh, bao gồm các chức năng gọi:

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

Dây

Một lối tắt cho phiên bản so sánh chuỗi đầu tiên:

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

strcmpkhông chính xác những gì mong đợi cmpở đây, nó trả lại -1, 0hoặc 1.

Người điều khiển tàu vũ trụ

PHP 7 đã giới thiệu toán tử tàu vũ trụ , nó hợp nhất và đơn giản hóa bằng / nhỏ hơn / lớn hơn so với các so sánh giữa các loại:

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

Sắp xếp theo nhiều lĩnh vực

Nếu bạn muốn sắp xếp chủ yếu theo foo, nhưng nếu foobằng nhau cho hai yếu tố sắp xếp theo baz:

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

Đối với những người quen thuộc, điều này tương đương với một truy vấn SQL với ORDER BY foo, baz.
Cũng xem phiên bản tốc ký rất gọn gàng nàycách tạo ra một chức năng so sánh như vậy một cách linh hoạt cho một số lượng phím tùy ý .

Sắp xếp vào một hướng dẫn, trật tự tĩnh

Nếu bạn muốn sắp xếp các thành phần vào một "thứ tự thủ công" như "foo", "bar", "baz" :

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

Đối với tất cả những điều trên, nếu bạn đang sử dụng PHP 5.3 trở lên (và bạn thực sự nên), hãy sử dụng các hàm ẩn danh cho mã ngắn hơn và để tránh có một hàm toàn cầu khác trôi nổi xung quanh:

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

Đó là cách đơn giản sắp xếp một mảng đa chiều phức tạp có thể. Một lần nữa, chỉ cần nghĩ về mặt giảng dạy PHP làm thế nào để biết mục nào trong hai mục là "lớn hơn" ; hãy để PHP thực hiện việc sắp xếp thực tế.

Ngoài ra, đối với tất cả các mục trên, để chuyển đổi giữa thứ tự tăng dần và giảm dần chỉ cần trao đổi $avà các $bđối số xung quanh. Ví dụ:

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

Sắp xếp một mảng dựa trên mảng khác

Và sau đó là đặc thù array_multisort, cho phép bạn sắp xếp một mảng dựa trên một mảng khác:

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

Kết quả dự kiến ​​ở đây sẽ là:

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

Sử dụng array_multisortđể đạt được điều đó:

array_multisort($array1, $array2);

Kể từ PHP 5.5.0, bạn có thể sử dụng array_columnđể trích xuất một cột từ một mảng đa chiều và sắp xếp mảng trên cột đó:

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

Kể từ PHP 7.0.0, bạn cũng có thể trích xuất các thuộc tính từ một mảng các đối tượng.


Nếu bạn có nhiều trường hợp phổ biến hơn, vui lòng chỉnh sửa câu trả lời này.


Hàm so sánh số không hoạt động đối với các giá trị float; Tôi chắc chắn bạn biết ý tôi là gì :)
Ja͢ck

1
Đối với thứ tự tĩnh, tôi sẽ áp dụng array_flip()để sử dụng tra cứu vị trí nhanh hơn, ví dụ $order[$a['foo']]thay vì array_search($a['foo'], $order).
Ja͢ck

Có thể là một chút chỉnh sửa lớn: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b nhưng nếu bạn nghĩ đó là một cải tiến và tôi đã bao gồm mọi thứ thiết yếu tôi có thể áp dụng nó.
Rizier123

@ Rizier123 Tôi chắc chắn hoan nghênh nỗ lực này, đó là một bài viết rất tốt; nhưng tôi thích nó hơn nếu bạn đăng nó dưới dạng câu trả lời riêng biệt, ngay cả khi nó rất giống nhau. Viết lại của bạn chứa rất nhiều chi tiết (chuyển qua tham chiếu, bảng lớn, v.v.), nhưng chi tiết đó làm mất tập trung từ phần giới thiệu trơn tru đến chủ đề cốt lõi của hoạt động của chức năng so sánh, IMHO. Tôi rõ ràng đề cập đến hướng dẫn nhiều lần về mục đích, bởi vì đó là nơi mà chi tiết như vậy nên được tra cứu; không cần phải lặp lại ở đây và làm sao lãng ý tưởng cốt lõi mà tôi đang cố gắng truyền đạt.
lừa dối

@deceze Thách thức chính, vì đây là một câu hỏi và trả lời tham khảo, là hiển thị thông tin nhỏ gọn và dễ đọc nhất có thể và giúp người dùng dễ dàng tìm thấy chức năng sắp xếp của họ. Tôi tinh chỉnh một vài điều: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b nhưng tôi vẫn phải suy nghĩ về nó, nếu nó rất hữu ích và có giá trị để gửi nó như là câu trả lời riêng biệt, vì nó là nội dung rất giống nhau
Rizier123

139

Vâng, hầu hết các phương pháp cơ bản đã được bao phủ bởi sự lừa dối, tôi sẽ cố gắng xem xét các loại sắp xếp khác

Sắp xếp với SPL

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

Đầu ra

c
b
a

SplMaxHeap

Lớp SplMaxHeap cung cấp các chức năng chính của một đống, giữ tối đa trên đầu trang.

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

SplMinHeap

Lớp SplMinHeap cung cấp các chức năng chính của một đống, giữ mức tối thiểu trên đầu trang.

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

Các loại sắp xếp khác

Sắp xếp bong bóng

Từ bài viết Wikipedia về Bubble Sort:

Sắp xếp bong bóng, đôi khi được gọi không chính xác là sắp xếp chìm, là một thuật toán sắp xếp đơn giản, hoạt động bằng cách lặp đi lặp lại danh sách cần sắp xếp, so sánh từng cặp vật phẩm liền kề và hoán đổi chúng nếu chúng sai thứ tự. Việc vượt qua danh sách được lặp lại cho đến khi không cần hoán đổi, điều này cho thấy danh sách đã được sắp xếp. Thuật toán lấy tên của nó từ cách các phần tử nhỏ hơn "bong bóng" lên đầu danh sách. Bởi vì nó chỉ sử dụng so sánh để hoạt động trên các yếu tố, nó là một loại so sánh. Mặc dù thuật toán rất đơn giản, hầu hết các thuật toán sắp xếp khác hiệu quả hơn cho các danh sách lớn.

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

Lựa chọn sắp xếp

Từ bài viết Wikipedia về Lựa chọn sắp xếp:

Trong khoa học máy tính, sắp xếp lựa chọn là một thuật toán sắp xếp, cụ thể là sắp xếp so sánh tại chỗ. Nó có độ phức tạp thời gian O (n2), làm cho nó không hiệu quả trong các danh sách lớn và thường hoạt động kém hơn so với loại chèn tương tự. Lựa chọn sắp xếp được ghi nhận vì tính đơn giản của nó và nó có lợi thế về hiệu suất so với các thuật toán phức tạp hơn trong các tình huống nhất định, đặc biệt khi bộ nhớ phụ bị hạn chế.

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

Sắp xếp chèn

Từ bài viết Wikipedia về sắp xếp chèn:

Sắp xếp chèn là một thuật toán sắp xếp đơn giản, xây dựng mảng được sắp xếp cuối cùng (hoặc danh sách) một mục tại một thời điểm. Nó kém hiệu quả hơn nhiều trong các danh sách lớn so với các thuật toán tiên tiến hơn như quicksort, heapsort hoặc hợp nhất sắp xếp. Tuy nhiên, sắp xếp chèn cung cấp một số lợi thế:

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

Vỏ ốc

Từ bài viết trên Wikipedia về Shellsort:

Shellsort, còn được gọi là phương pháp Shell sort hoặc phương pháp của Shell, là một loại so sánh tại chỗ. Nó khái quát một loại trao đổi, chẳng hạn như chèn hoặc sắp xếp bong bóng, bằng cách bắt đầu so sánh và trao đổi các yếu tố với các yếu tố cách xa nhau trước khi kết thúc với các yếu tố lân cận.

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

Lược sắp xếp

Từ bài viết Wikipedia về Comb sort:

Comb sort là một thuật toán sắp xếp tương đối đơn giản ban đầu được thiết kế bởi Wlodzimierz Dobosiewicz vào năm 1980. Sau đó, nó đã được Stephen Lacey và Richard Box khám phá lại vào năm 1991. Comb sort cải thiện về sắp xếp bong bóng.

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

Hợp nhất sắp xếp

Từ bài viết Wikipedia về Hợp nhất sắp xếp:

Trong khoa học máy tính, một loại sắp xếp hợp nhất (cũng thường được đánh vần là một thuật toán sắp xếp dựa trên so sánh O (n log n). Hầu hết các triển khai tạo ra một loại ổn định, có nghĩa là việc triển khai duy trì thứ tự đầu vào của các phần tử bằng nhau trong đầu ra được sắp xếp

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

Sắp xếp nhanh chóng

Từ bài viết Wikipedia trên Quicksort:

Quicksort, hay sắp xếp trao đổi phân vùng, là một thuật toán sắp xếp được phát triển bởi Tony Hoare, trung bình, làm cho O (n log n) so sánh để sắp xếp n mục. Trong trường hợp xấu nhất, nó làm cho so sánh O (n2), mặc dù hành vi này rất hiếm.

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

Sắp xếp hoán vị

Từ bài viết Wikipedia về Sắp xếp hoán vị:

Sắp xếp hoán vị, tiến hành bằng cách tạo ra các hoán vị có thể có của mảng / danh sách đầu vào cho đến khi khám phá ra thứ được sắp xếp.

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

Loại radix

Từ bài viết Wikipedia về Radix sort:

Trong khoa học máy tính, radix sort là một thuật toán sắp xếp số nguyên không so sánh, sắp xếp dữ liệu với các khóa nguyên bằng cách nhóm các khóa theo các chữ số riêng lẻ có cùng vị trí và giá trị quan trọng.

// 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 bạn đã bao gồm tất cả các điều cơ bản .. tôi đã phải tìm một cách khác để có liên quan :)
Baba

5
Tôi không thấy có gì sai với các phương pháp sắp xếp học thuật hơn :) rất ít hữu ích cho hầu hết các ứng dụng nhưng đôi khi chúng có thể được yêu cầu / yêu cầu rất hữu ích để có một tài liệu tham khảo đặc biệt là vì tôi đã quên về hầu hết những điều này theo thời gian
Dave

Trên thực tế, để sắp xếp nhanh, nên chọn trục làm trung vị của ba giá trị: các phần tử đầu tiên, giữa và cuối . Đây là ví dụ của tôi cho lựa chọn trục. Điều đó cho phép tránh mảng được sắp xếp ngược trong trường hợp xấu nhất (điều này gây ra sự O(n^2)so sánh nếu chúng ta chỉ sử dụng phần tử đầu tiên làm trục)
Alma Do

Tôi đã nghe nói rằng spl hoạt động nhanh hơn so với sắp xếp mảng bình thường. Có đúng không?
jewhuq

Tôi đồng ý với Dave, ngày nay, hầu như fw đã bao gồm rằng tại sao tôi hiếm khi nhớ hoặc sử dụng nó.
Mike Nguyễn

43

Sắp xếp ổn định

Giả sử bạn có một mảng như thế này:

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

Và bây giờ bạn chỉ muốn sắp xếp chữ cái đầu tiên:

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

Kết quả là thế này:

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

Các loại không ổn định!

Người quan sát sắc sảo có thể nhận thấy rằng thuật toán sắp xếp mảng (QuickSort) không tạo ra kết quả ổn định và thứ tự ban đầu giữa các từ của cùng một chữ cái đầu tiên không được giữ nguyên. Trường hợp này là tầm thường và chúng ta nên so sánh toàn bộ chuỗi, nhưng giả sử trường hợp sử dụng của bạn phức tạp hơn, chẳng hạn như hai loại liên tiếp trên các trường khác nhau không nên hủy bỏ công việc của nhau.

Biến đổi Schwartzian

Biến đổi Schwartzian , còn được gọi là thành ngữ trang trí sắp xếp không trang trí, tạo hiệu ứng sắp xếp ổn định với thuật toán sắp xếp không ổn định vốn có.

Đầu tiên, bạn trang trí từng phần tử mảng bằng một mảng khác bao gồm khóa chính (giá trị) và khóa phụ (chỉ mục hoặc vị trí của nó):

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

Điều này biến đổi mảng thành này:

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

Bây giờ, chúng tôi điều chỉnh bước so sánh; chúng tôi so sánh lại chữ cái đầu tiên, nhưng nếu chúng giống nhau, khóa phụ được sử dụng để giữ nguyên thứ tự ban đầu:

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

Sau đó, chúng tôi không trang bị:

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

Kết quả cuối cùng:

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

Còn tái sử dụng thì sao?

Bạn phải viết lại hàm so sánh của bạn để làm việc với các phần tử mảng được chuyển đổi; bạn có thể không muốn chỉnh sửa các chức năng so sánh tế nhị của mình, vì vậy đây là trình bao bọc cho chức năng so sánh:

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

Hãy viết bước sắp xếp bằng hàm này:

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

Voila! Mã so sánh nguyên sơ của bạn đã trở lại.


Cụm từ của bạn "ảnh hưởng đến một loại ổn định với thuật toán sắp xếp không ổn định vốn có" là thời điểm ah-ha đối với tôi. Trang wikipedia không có đề cập đến từ ổn định, mà dường như tôi là vẻ đẹp của sự biến đổi. Xấu hổ.
Tyler Collier

1
@TylerCollier Vâng, bạn cần đọc giữa các dòng của tài liệu tham khảo Wikipedia đó ... Tôi đã cứu bạn những rắc rối khi làm điều đó ;-)
Ja͢ck

15

Kể từ phiên bản PHP 5.3 với các bao đóng, cũng có thể sử dụng một bao đóng để xác định thứ tự sắp xếp của bạn.

Ví dụ: giả sử mảng $ là một mảng các đối tượng có chứa thuộc tính tháng.

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

Chỉ cần nhớ rằng điều này sẽ xóa mọi thứ tự tương đối trước đó (ví dụ: đối tượng "Tháng 7" đầu tiên trong danh sách được sắp xếp trước có thể kết thúc ở cuối nhóm các đối tượng tháng 7 sau khi sắp xếp). Xem "Sắp xếp ổn định" ở trên.
George Langley

9

LINQ

Trong .NET, LINQ thường được sử dụng để sắp xếp, cung cấp cú pháp đẹp hơn nhiều so với các hàm so sánh, đặc biệt là khi các đối tượng cần được sắp xếp theo nhiều trường. Có một số cổng LINQ sang PHP, bao gồm thư viện YaLinqo *. Với nó, các mảng có thể được sắp xếp với một dòng duy nhất mà không cần viết các hàm so sánh phức tạp.

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

So sánh có thể được tùy chỉnh thêm bằng cách chuyển một cuộc gọi lại như một đối số thứ hai, ví dụ:

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

Ở đây, '$v->count'là một tốc ký cho function ($v) { return $v->count; }(hoặc có thể được sử dụng). Các chuỗi phương thức này trả về các trình vòng lặp, các trình vòng lặp có thể được chuyển đổi thành các mảng bằng cách thêm ->toArray()vào cuối nếu cần.

Bên trong, orderByvà các phương pháp có liên quan gọi mảng sắp xếp các chức năng thích hợp ( uasort, krsort, multisort, usortvv).

LINQ chứa nhiều phương thức khác được lấy cảm hứng từ SQL: lọc, nhóm, nối, tổng hợp, v.v ... Nó phù hợp nhất cho các trường hợp khi các phép biến đổi phức tạp trên mảng và các đối tượng cần được thực hiện mà không cần dựa vào cơ sở dữ liệu.

* được phát triển bởi tôi, xem readme để biết thêm chi tiết và so sánh với các cổng LINQ khác


3

Sắp xếp đa chiều theo giá trị chính

Sắp xếp tự nhiên của một mảng nhiều chiều theo một giá trị khóa và cũng giữ thứ tự ban đầu (không xáo trộn các khóa chính):

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

Trường hợp thử nghiệm:

$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

Rất thuận tiện để sắp xếp các mảng với chức năng được sắp xếp từ Nspl :

Sắp xếp cơ bản

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

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

Sắp xếp theo kết quả chức năng

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

Sắp xếp mảng đa chiều

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

Sắp xếp mảng các đối tượng

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

Sắp xếp với chức năng so sánh

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

Bạn có thể xem tất cả các ví dụ ở đây .


2

Nếu bạn muốn đặt hàng theo giá trị chính, thì bạn có thể thực hiện một dòng, thanh lịch và rõ ràng. Điều này sẽ đặt hàng theo giá tăng dần. Sử dụng mảng_multisort và mảng_column.

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

để sản xuất

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

1

Trang này rất toàn diện, nhưng tôi muốn nói thêm một chút về tiện ích tuyệt vời của toán tử tàu vũ trụ (toán tử so sánh ba chiều) - một đứa con xinh đẹp của PHP7 +.

Sử dụng toán tử tàu vũ trụ để thực hiện nhiều điều kiện sắp xếp

Điều này làm cho những bước tiến lớn trong việc giảm phình mã và cải thiện khả năng đọc.

Khi viết hàm sắp xếp tùy chỉnh ( usort()/ uasort()/ uksort()) của bạn để xử lý nhiều điều kiện, bạn chỉ cần viết các mảng cân bằng ở hai bên của toán tử và trả về kết quả. Không có khối điều kiện lồng nhau hoặc nhiều lợi nhuận.

Các phần tử từ cả hai phía của toán tử sẽ được dịch chuyển từ trái sang phải, từng phần một và trả về đánh giá ngay khi gặp phải một ràng buộc hoặc khi tất cả các phần tử được so sánh.

Dữ liệu mẫu cho các cuộc biểu tình của tôi:

$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' => ''
    ]
];

Trình diễn (để tránh sự phình to của trang Stackoverflow, vui lòng xem liên kết demo cho các đầu ra):

  • Sắp xếp logic:

    1. boolean DESC (false = 0, true = 1, do đó, trước khi giả mạo)
    2. phao ASC

      uasort($multidimArray, function($a, $b) {
          return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']];
      });
  • Sắp xếp logic:

    1. ASC hỗn hợp
    2. đối tượng 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ắp xếp logic:

    1. số lượng tài sản của đối tượng ASC
    2. khả năng lặp lại của hỗn hợp DESC
    3. chiều dài natString 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']];
      });

Cú pháp này cho phép bạn sắp xếp các giá trị, kết quả chức năng, dữ liệu được lồng sâu và hướng sắp xếp theo kiểu thanh lịch. Điều này chắc chắn đáng để đưa vào công cụ php của bạn ... cho các trường hợp khi bạn đang xử lý dữ liệu không phải là cơ sở dữ liệu - vì dĩ nhiên SQL sẽ là một kỹ thuật hợp lý hơn nhiều.

Theo quyết định của riêng bạn, từ PHP7.4, bạn có thể sử dụng cú pháp mũi tên với các hàm ẩn danh này. Kịch bản tương tự với cú pháp mũi tên .


0

Nếu ai đó muốn một giải pháp đơn giản hơn để thao tác với các mảng, chỉ cần sử dụng gói Bộ sưu tập Laravel có chức năng sortBy được triển khai cho phép bạn sắp xếp theo các phím một cách đơn giản.

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

tức là, để sắp xếp đầu tiên theo a, sau đó b, sau đó c, mệnh đề đúng sẽ là

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

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


-1

Có một số cách để sắp xếp một mảng. Tôi sẽ đề cập đến một số phương thức để thực hiện nhiệm vụ đó. Trong tất cả, tôi sẽ đưa ra một mảng số nguyên được gọi là '$ number'.

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

Đây là cách bình thường để tạo ra một mảng. Giả sử rằng, tôi muốn sắp xếp mảng đó theo thứ tự tăng dần. Cho rằng, phương thức 'sort ()' có thể được sử dụng.

<?php

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

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

Bây giờ hãy xem xét đầu ra của điều đó,

nhập mô tả hình ảnh ở đây

Bạn có thể thấy mảng số in được sắp xếp. Nếu bạn muốn mảng số đó được sắp xếp theo thứ tự giảm dần, phương thức 'rsort ()' có thể được sử dụng cho tác vụ đó.

<?php

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

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

xem xét đầu ra ..

nhập mô tả hình ảnh ở đây

Bây giờ mảng được sắp xếp theo thứ tự giảm dần. Chúng ta hãy xem xét một mảng kết hợp. Tôi sẽ đưa ra một mảng kết hợp (mảng kết hợp có nghĩa là, Một mảng có mỗi chỉ mục có giá trị khóa duy nhất.) Như thế này,

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

Vì vậy, bây giờ tôi muốn sắp xếp mảng này theo thứ tự tăng dần theo giá trị của chúng. Phương thức'asort () 'có thể được sử dụng cho điều đó.

<?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."  ";
    }
?>

Nếu sắp xếp thứ tự giảm dần theo giá trị của chúng, phương thức 'arsort ()' có thể được sử dụng. Giả sử bạn muốn sắp xếp mảng đó theo giá trị khóa của chúng. Trong trường hợp này, phương thức 'ksort ()' có thể được sử dụng.

<?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."  ";
     }
?>

Bây giờ hãy xem xét đầu ra. nhập mô tả hình ảnh ở đây

Bây giờ mảng được sắp xếp theo giá trị khóa của chúng. Nếu bạn muốn sắp xếp mảng theo thứ tự giảm dần theo giá trị khóa của chúng, có thể sử dụng phương thức 'krsort ()'.

<?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."  ";
    }
?>

Bây giờ mảng kết hợp được sắp xếp theo thứ tự giảm dần theo giá trị khóa của chúng. Nhìn vào đầu ra. nhập mô tả hình ảnh ở đây

Đây là một số phương pháp để sắp xếp một mảng theo thứ tự tăng dần hoặc giảm dần trong php. Tôi hy vọng bạn có thể có một ý tưởng. Cảm ơn bạn!


Không lừa dối đã bao gồm những hiểu biết này với: "Sự khác biệt giữa những điều đó chỉ đơn thuần là liệu các liên kết giá trị khóa có được giữ (các hàm" a ") hay không, cho dù nó sắp xếp từ thấp đến cao hay ngược (" r "), cho dù đó là sắp xếp các giá trị hoặc khóa ("k") và cách so sánh các giá trị ("nat" so với bình thường). " trong câu trả lời được chấp nhận?
mickmackusa

-2

Đơn giản nhất là sử dụng hàm usort để sắp xếp mảng mà không có bất kỳ vòng lặp nào: Dưới đây là một ví dụ:

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

Điều này sẽ sắp xếp theo thứ tự mong muốn:

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

Điều này sẽ sắp xếp theo thứ tự tăng dần:

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

1
1) Ví dụ và mã không nhất quán. 2) Điều này đã được giải thích chi tiết rõ ràng trong các câu trả lời ở trên. 3) Bạn có thể cố gắng trả lời một câu hỏi khác không?
lừa dối
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.