Sắp xếp mảng đa chiều theo nhiều phím


83

Tôi đang cố gắng sắp xếp một mảng nhiều chiều theo nhiều khóa và tôi không biết bắt đầu từ đâu. Tôi đã xem xét uasort, nhưng không chắc làm thế nào để viết một hàm cho những gì tôi cần.

Tôi cần sắp xếp theo trạng thái, sau đó là event_type, sau đó là ngày.

Mảng của tôi trông như thế này:

    Array
(
    [0] => Array
        (
            [ID] => 1
            [title] => Boring Meeting
            [date_start] => 2010-07-30
            [time_start] => 06:45:PM
            [time_end] => 
            [state] => new-york
            [event_type] => meeting
        )

    [1] => Array
        (
            [ID] => 2
            [title] => Find My Stapler
            [date_start] => 2010-07-22
            [time_start] => 10:45:AM
            [time_end] => 
            [state] => new-york
            [event_type] => meeting
        )

    [2] => Array
        (
            [ID] => 3
            [title] => Mario Party
            [date_start] => 2010-07-22
            [time_start] => 02:30:PM
            [time_end] => 07:15:PM
            [state] => new-york
            [event_type] => party
        )

    [3] => Array
        (
            [ID] => 4
            [title] => Duct Tape Party
            [date_start] => 2010-07-28
            [time_start] => 01:00:PM
            [time_end] => 
            [state] => california
            [event_type] => party
        )
...... etc

1
… Và bạn muốn sắp xếp nó như thế nào?
dối trá

có thể trùng lặp của Phân loại mảng đa chiều trong PHP
outis

Câu trả lời:


181

Bạn cần array_multisort

$mylist = array(
    array('ID' => 1, 'title' => 'Boring Meeting', 'event_type' => 'meeting'),
    array('ID' => 2, 'title' => 'Find My Stapler', 'event_type' => 'meeting'),
    array('ID' => 3, 'title' => 'Mario Party', 'event_type' => 'party'),
    array('ID' => 4, 'title' => 'Duct Tape Party', 'event_type' => 'party')
);

# get a list of sort columns and their data to pass to array_multisort
$sort = array();
foreach($mylist as $k=>$v) {
    $sort['title'][$k] = $v['title'];
    $sort['event_type'][$k] = $v['event_type'];
}
# sort by event_type desc and then title asc
array_multisort($sort['event_type'], SORT_DESC, $sort['title'], SORT_ASC,$mylist);

Kể từ PHP 5.5.0:

array_multisort(array_column($mylist, 'event_type'), SORT_DESC,
                array_column($mylist, 'title'),      SORT_ASC,
                $mylist);

$mylist Hiện tại là:

array (
  0 => 
  array (
    'ID' => 4,
    'title' => 'Duct Tape Party',
    'event_type' => 'party',
  ),
  1 => 
  array (
    'ID' => 3,
    'title' => 'Mario Party',
    'event_type' => 'party',
  ),
  2 => 
  array (
    'ID' => 1,
    'title' => 'Boring Meeting',
    'event_type' => 'meeting',
  ),
  3 => 
  array (
    'ID' => 2,
    'title' => 'Find My Stapler',
    'event_type' => 'meeting',
  ),
)

@Rob Tôi rất tò mò về cách bạn sắp xếp date_start
frazras

5
"Bữa tiệc băng keo" là gì?
gdaniel

Đối với PHP <5.5, có polyfill cho array_columnhàm github.com/ramsey/array_column . Vì vậy, có thể sử dụng cách thanh lịch hơn từ đoạn mã thứ hai trên các phiên bản cũ.
userlond

15

Bạn có thể làm điều đó với usort. Đối $cmp_functionsố có thể là:

function my_sorter($a, $b) {
    $c = strcmp($a['state'], $b['state']);
    if($c != 0) {
        return $c;
    }

    $c = strcmp($a['event_type'], $b['event_type']);
    if($c != 0) {
        return $c;
    }

    return strcmp($a['date_start'], $b['date_start']);
}

Đối với một số trường tùy ý trong PHP 5.3, bạn có thể sử dụng các bao đóng để tạo một hàm so sánh:

function make_cmp($fields, $fieldcmp='strcmp') {
    return function ($a, $b) use (&$fields) {
        foreach ($fields as $field) {
            $diff = $fieldcmp($a[$field], $b[$field]);
            if($diff != 0) {
                return $diff;
            }
        }
        return 0;
    }
}

usort($arr, make_cmp(array('state', 'event_type', 'date_start')))

Đối với một số trường tùy ý thuộc các kiểu khác nhau trong PHP 5.3:

function make_cmp($fields, $dfltcmp='strcmp') {
    # assign array in case $fields has no elements
    $fieldcmps = array();
    # assign a comparison function to fields that aren't given one
    foreach ($fields as $field => $cmp) {
        if (is_int($field) && ! is_callable($cmp)) {
            $field = $cmp;
            $cmp = $dfltcmp;
        }
        $fieldcmps[$field] = $cmp;
    }
    return function ($a, $b) use (&$fieldcmps) {
        foreach ($fieldcmps as $field => $cmp) {
            $diff = call_user_func($cmp, $a[$field], $b[$field]);
            if($diff != 0) {
                return $diff;
            }
        }
        return 0;
    }
}

function numcmp($a, $b) {
    return $a - $b;
}
function datecmp($a, $b) {
    return strtotime($a) - strtotime($b);
}
/**
 * Higher priority come first; a priority of 2 comes before 1.
 */
function make_evt_prio_cmp($priorities, $default_priority) {
    return function($a, $b) use (&$priorities) {
        if (isset($priorities[$a])) {
            $prio_a = $priorities[$a];
        } else {
            $prio_a = $default_priority;
        }
        if (isset($priorities[$b])) {
            $prio_b = $priorities[$b];
        } else {
            $prio_b = $default_priority;
        }
        return $prio_b - $prio_a;
    };
}

$event_priority_cmp = make_evt_prio_cmp(
    array('meeting' => 5, 'party' => 10, 'concert' => 7), 
    0);

usort($arr, make_cmp(array('state', 'event' => $event_priority_cmp, 'date_start' => 'datecmp', 'id' => 'numcmp')))

1
Bạn có thể đơn giản hóa việc lồng ghép một chút và tôi nghĩ bạn sẽ cần phải làm gì đó nhiều hơn với ngày tháng, nhưng cách tiếp cận có vẻ tốt nhất cho đến nay.
deceze

1
Điều thú vị về định dạng '% Y-% m-% d' được sử dụng trong mảng mẫu là so sánh chuỗi hoạt động để so sánh ngày.
outis

9

PHP7 Giúp việc sắp xếp theo nhiều cột trở nên SIÊU dễ dàng với toán tử phi thuyền ( <=>) hay còn gọi là "Toán tử so sánh kết hợp" hoặc "Toán tử so sánh ba chiều".

Tài nguyên: https://wiki.php.net/rfc/combined-comparison-operator

Việc sắp xếp theo nhiều cột cũng đơn giản như viết mảng cân bằng / quan hệ trên cả hai mặt của toán tử. Dễ dàng thực hiện!

Tôi đã không sử dụng uasort()vì tôi không thấy cần thiết phải giữ lại các chỉ mục gốc.

Mã: ( Demo )

$array = [
    ['ID' => 1, 'title' => 'Boring Meeting', 'date_start' => '2010-07-30', 'event_type' => 'meeting', 'state' => 'new-york'],
    ['ID' => 2, 'title' => 'Find My Stapler', 'date_start' => '2010-07-22', 'event_type' => 'meeting', 'state' => 'new-york'],
    ['ID' => 3, 'title' => 'Mario Party', 'date_start' => '2010-07-22', 'event_type' => 'party', 'state' => 'new-york'],
    ['ID' => 4, 'title' => 'Duct Tape Party', 'date_start' => '2010-07-28', 'event_type' => 'party', 'state' => 'california']
];

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

var_export($array);

Đầu ra

array (
  0 => 
  array (
    'ID' => 4,
    'title' => 'Duct Tape Party',
    'date_start' => '2010-07-28',
    'event_type' => 'party',
    'state' => 'california',
  ),
  1 => 
  array (
    'ID' => 2,
    'title' => 'Find My Stapler',
    'date_start' => '2010-07-22',
    'event_type' => 'meeting',
    'state' => 'new-york',
  ),
  2 => 
  array (
    'ID' => 1,
    'title' => 'Boring Meeting',
    'date_start' => '2010-07-30',
    'event_type' => 'meeting',
    'state' => 'new-york',
  ),
  3 => 
  array (
    'ID' => 3,
    'title' => 'Mario Party',
    'date_start' => '2010-07-22',
    'event_type' => 'party',
    'state' => 'new-york',
  ),
)

ps Cú pháp mũi tên với PHP7.4 trở lên ( Demo ) ...

usort($array, fn($a, $b) => [$a['state'], $a['event_type'], $a['date_start']] <=> [$b['state'], $b['event_type'], $b['date_start']]);

3
class Sort {
    private $actual_order = 'asc';
    private $actual_field = null;

    public function compare_arrays($array1, $array2) {

        if ($array1[$this->actual_field] == $array2[$this->actual_field]) {
            return 0;
        }
        elseif ($array1[$this->actual_field] > $array2[$this->actual_field]) {
            return ($this->actual_order == 'asc' ? 1 : -1);
        }
        else {
            return ($this->actual_order == 'asc' ? -1 : 1);
        }

    }


    public function order_array(&$array) {

        usort($array, array($this, 'compare_arrays'));

    }


    public function __construct ($field, $actual_order = 'asc') {
        $this->actual_field = $field;
        $this->actual_order = $actual_order;
    }

}

// use

$sort = new Sort ("state");

$sort->order_array($array);

3

Tôi đã thử mã bên dưới và tôi thành công

mã mảng

$songs =  array(
        '1' => array('artist'=>'Smashing Pumpkins', 'songname'=>'Soma'),
        '2' => array('artist'=>'The Decemberists', 'songname'=>'The Island'),
        '3' => array('artist'=>'Fleetwood Mac', 'songname' =>'Second-hand News')
);

gọi hàm sắp xếp mảng

$songs = subval_sort($songs,'artist'); 
print_r($songs);

sắp xếp mảng chức năng

function subval_sort($a,$subkey) {
    foreach($a as $k=>$v) {
        $b[$k] = strtolower($v[$subkey]);
    }
    asort($b);
    foreach($b as $key=>$val) {
        $c[] = $a[$key];
    }
    return $c;
}

nếu chức năng sắp xếp ngược mảng

function subval_sort($a,$subkey) {
        foreach($a as $k=>$v) {
            $b[$k] = strtolower($v[$subkey]);
        }
        arsort($b);
        foreach($b as $key=>$val) {
            $c[] = $a[$key];
        }
        return $c;
    }

2

Cải thiện mã thiên tài của @Stijn Leenknegt, đây là chức năng thực dụng 2 xu của tôi:

$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);

function make_cmp(array $sortValues)
{
    return function ($a, $b) use (&$sortValues) {
        foreach ($sortValues as $column => $sortDir) {
            $diff = strcmp($a[$column], $b[$column]);
            if ($diff !== 0) {
                if ('asc' === $sortDir) {
                    return $diff;
                }
                return $diff * -1;
            }
        }
        return 0;
    };
}

usort($data, make_cmp(['volume' => "desc", 'edition' => "asc"]));

-1

nếu bạn muốn sắp xếp mảng đa chiều

mảng đầu tiên là:

$results['total_quote_sales_person_wise']['quote_po'];

thứ hai là:

$results['total_quote_sales_person_wise']['quote_count'];

cả mảng đa phương thức này mà bạn muốn sắp xếp thứ tự giảm dần tại một thời điểm thì hãy sử dụng mã này:

array_multisort($results['total_quote_sales_person_wise']['quote_po'],SORT_DESC, $results['total_quote_sales_person_wise']['quote_count'],SORT_DESC);
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.