Làm thế nào để sắp xếp mảng đa chiều theo giá trị?


1129

Làm thế nào tôi có thể sắp xếp mảng này theo giá trị của khóa "thứ tự"? Mặc dù các giá trị hiện tại là tuần tự, nhưng chúng sẽ không luôn luôn như vậy.

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


cách nhanh nhất là sử dụng mô đun mảng sắp xếp đẳng cấu , hoạt động tự nhiên trong cả trình duyệt và nút, hỗ trợ mọi loại đầu vào, trường được tính toán và thứ tự sắp xếp tùy chỉnh.
Lloyd

Câu trả lời:


1734

Hãy thử một usort , Nếu bạn vẫn còn trên PHP 5.2 hoặc sớm hơn, bạn sẽ phải xác định một chức năng sắp xếp đầu tiên:

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

usort($myArray, 'sortByOrder');

Bắt đầu trong PHP 5.3, bạn có thể sử dụng một hàm ẩn danh:

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

Và cuối cùng với PHP 7, bạn có thể sử dụng toán tử tàu vũ trụ :

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

Để mở rộng điều này thành sắp xếp đa chiều, hãy tham khảo các phần tử sắp xếp thứ hai / thứ ba nếu phần tử đầu tiên bằng 0 - giải thích tốt nhất dưới đây. Bạn cũng có thể sử dụng điều này để sắp xếp các yếu tố phụ.

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

Nếu bạn cần giữ lại các liên kết chính, hãy sử dụng uasort()- xem so sánh các hàm sắp xếp mảng trong hướng dẫn


2
Phrasing của tôi là một chút tắt, tôi sẽ chỉnh sửa nó. Ý tôi là nếu bạn không dùng PHP 5.3, bạn cần tạo một hàm đặc biệt chỉ dành cho cách sắp xếp cụ thể này (Điều này không thực sự thanh lịch). Nếu không, bạn có thể sử dụng một chức năng ẩn danh ngay tại đó.
Christian Studer

23
@Jonathan: Bạn thực sự không thể thấy hầu hết các công việc mà PHP làm. Nó lấy mảng và bắt đầu với hai phần tử, được truyền cho hàm do người dùng định nghĩa này. Hàm của bạn sau đó chịu trách nhiệm so sánh chúng: Nếu phần tử đầu tiên lớn hơn phần tử thứ hai, trả về một số nguyên dương, nếu nó nhỏ hơn, trả về phần tử âm. Nếu chúng bằng nhau, trả về 0. PHP sau đó gửi hai phần tử khác đến hàm của bạn và tiếp tục làm như vậy, cho đến khi mảng được sắp xếp. Hàm ở đây rất ngắn, có thể phức tạp hơn nhiều nếu bạn không so sánh các số nguyên.
Christian Studer

61
Protip: sử dụng uasort()nếu bạn muốn bảo tồn các phím mảng.
thaddeusmt

15
Hãy cẩn thận nếu các giá trị có thể sắp xếp là số thập phân. Nếu hàm sắp xếp nhận $ a = 1 và $ b = 0,1, thì chênh lệch là 0,9, nhưng hàm trả về một int, trong trường hợp này là 0, vì vậy $ a và $ b được coi là bằng nhau và được sắp xếp không chính xác. Thật đáng tin cậy hơn để so sánh nếu $ a lớn hơn $ b hoặc bằng và trả về -1, 1 hoặc 0 tương ứng.
Greenlandi

37
Phải mất một thời gian để tìm hiểu. Để sắp xếp thứ tự ngược lại (DESC), bạn có thể chuyển $ a và $ b. Vì vậy, $ b ['order'] - $ a ['order']
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 Tôi rất vui lòng giúp đỡ, nhưng hãy xem xét đề xuất của nhà sản xuất có thể hiệu quả hơn và chắc chắn gọn gàng hơn!
o0 '.

1
@Lohoris chắc chắn anh bạn tôi cũng đang kiểm tra điều đó. Hôm qua sẽ là một ngày khó khăn hơn trong văn phòng nếu tôi không tìm thấy câu hỏi này :-)
Gogol

hmm không thể thêm câu trả lời .. tôi cũng đặt nó ở đây vì tôi không cần những điểm ngu ngốc đó , $ key1, $ key2, $ key3) {$ sorter = mảng (); $ ret = mảng (); đặt lại (mảng $); foreach ($ mảng là $ ii => $ va) {$ sorter [$ ii] = getprice ($ va [$ key1] [$ key2] [$ key3]); } arsort ($ sorter); foreach ($ sorter là $ ii => $ va) {$ ret [$ ii] = $ mảng [$ ii]; } $ mảng = $ ret; }
Jaxx0rr

3
Dễ dàng áp dụng hơn nhiều so với câu trả lời trên
Marcel

1
BẠN THẬT TUYỆT VỜI!! CÔNG TRÌNH THÍCH CHARM CHO PHP 7.2 CẢM ƠN RẤT NHIỀU :)
Kam Meat

270

Tôi sử dụng chức năng này:

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
Hoạt động rất tốt. Các giải pháp độc đáo có thể thêm một hướng sắp xếp. Cảm ơn!
Ivo Pereira

2
Đối với một giải pháp thay thế hỗ trợ các hướng sắp xếp và nhiều tính năng bổ sung, bạn có thể muốn xem câu trả lời của tôi ở đây - nó cũng có lợi thế là nó không sử dụng array_multisortvà do đó không cần phải phân bổ $sort_col, tiết kiệm thời gian và bộ nhớ .
Jon

Hoạt động rất tốt cho tôi, nhưng ... tại sao cần phải chỉ định &$arrthay vì chỉ $arr?
Radu Murzea

2
@RaduMurzea vì vậy mảng được truyền bằng tham chiếu và có thể được sửa đổi bởi hàm, thay vì hàm nhận bản sao
Tom Haigh

1
@AdrianP. : mảng được truyền bằng tham chiếu nên nó sẽ sửa đổi mảng đã qua thay vì trả về một bản sao được sắp xếp
Tom Haigh

72

Tôi thường sử dụng usort , và vượt qua chức năng so sánh của riêng tôi. Trong trường hợp này, nó rất đơn giản:

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

Trong PHP 7 sử dụng toán tử tàu vũ trụ:

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

4
Khỉ thật, tôi chậm hơn 30 giây. Không phải là $ a - $ b mặc dù?
Christian Studer

3
Tôi luôn nhận sai điều này. Hãy để tôi suy nghĩ từ hướng dẫn: giá trị trả về phải nhỏ hơn 0 nếu đối số thứ nhất được coi là nhỏ hơn giá trị thứ hai. Vì vậy, nếu $a['order']là 3, và $b['order']là 6, tôi sẽ trả về -3. Chính xác?
Jan Fabry

3
Vâng, bạn trả về b - a, vì vậy nó sẽ là 3. Và do đó sắp xếp không chính xác.
Christian Studer

26
Ah. ĐỒNG Ý. Tôi đã sử dụng số học phi logic, trong đó ý tưởng trong đầu bạn không khớp với những từ bạn tạo ra. Điều này được nghiên cứu thường xuyên nhất vào các buổi chiều thứ Sáu.
Jan Fabry

trong một số trường hợp, câu trả lời ở trên là trả về kết quả sai .. tham chiếu stackoverflow.com/questions/50636981/NH
Bilal Ahmed

45

Một cách tiếp cận để đạt được điều này sẽ như thế này

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

Kết quả:

    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

Để sắp xếp mảng theo giá trị của khóa "title", hãy sử dụng:

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

strcmp so sánh các chuỗi.

uasort () duy trì các khóa mảng như đã được xác định.


strcmp là một trợ giúp đáng chú ý cho các loại varchar, tôi thích câu trả lời này ngắn và nhanh
StudioX

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

Điều này chăm sóc cả bảng chữ cái in hoa và in thường.


4
Làm thế nào điều này trả lời câu hỏi sắp xếp theo một khóa mảng cụ thể?
Seano

12

sử dụng array_multisort(),array_map()

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

print_r($array);

BẢN GIỚI THIỆU


Lưu ý rằng phương pháp này sẽ phát ra một thông báo. array_multisorttham chiếu đó là tham số đầu tiên.
Kami Yang

5

Cách tiếp cận linh hoạt nhất sẽ là sử dụng phương pháp này

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

đây là lý do tại sao:

  • Bạn có thể sắp xếp theo bất kỳ phím nào (cũng được lồng như 'key1.key2.key3'hoặc ['k1', 'k2', 'k3'])

  • Hoạt động cả trên mảng kết hợp và không kết hợp ( $assoccờ)

  • Nó không sử dụng tham chiếu - trả về mảng được sắp xếp mới

Trong trường hợp của bạn, nó sẽ đơn giản như:

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

Phương pháp này là một phần của thư viện này .


1

Hãy đối mặt với nó: php KHÔNG có chức năng đơn giản để xử lý đúng mọi kịch bản sắp xếp mảng.

Thủ tục này là trực quan, có nghĩa là gỡ lỗi và bảo trì nhanh hơn:

// 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
"Hãy đối mặt với nó: php KHÔNG có chức năng đơn giản để xử lý đúng mọi kịch bản sắp xếp mảng." Đó chính xác là những gì usort / ksort / asort được thiết kế cho ^^ '
Ben Cassinat

3
Trên thực tế PHP rất nhiều hàm sắp xếp có thể được sử dụng để xử lý mọi kịch bản sắp xếp mảng.
axiac

Liên quan đến gỡ lỗi và bảo trì, việc sử dụng globallà một lá cờ đỏ khổng lồ và thường không được khuyến khích . Tại sao lại mysql_fetch_arrayđược chứng minh cho câu hỏi này thay vì mảng nguồn của OP và không có lời giải thích nào về việc mã của bạn đang làm gì và người ta có thể mong đợi kết quả sẽ như thế nào? Nhìn chung đây là một cách tiếp cận rất phức tạp để đạt được kết quả cuối cùng mong muốn.
fyrye

@tonygil Tôi không thể xác định kết quả mong đợi của bạn là gì từ câu trả lời của bạn và bộ dữ liệu của OP. Nó có thể rõ ràng với bạn, nhưng tôi không biết câu trả lời của bạn trả lời câu hỏi của OP như thế nào. Tuy nhiên, bạn có thể chuyển qua tham chiếu thay vì sử dụng globalxem: 3v4l.org/FEeFC Điều này tạo ra một biến được xác định rõ ràng, thay vì một biến có thể được thay đổi và truy cập trên toàn cầu.
fyrye

0

Bạn cũng có thể sắp xếp mảng đa chiều cho nhiều giá trị như

$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"
    ],

];

với

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

Đầu ra sử dụng 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) sử dụng strcmp sẽ là một lựa chọn tốt để so sánh các chuỗ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.