[php] 여러 키로 다차원 배열 정렬

여러 키로 다차원 배열을 정렬하려고하는데 어디서부터 시작해야할지 모르겠습니다. uasort를 살펴 보았지만 필요한 함수를 작성하는 방법을 잘 모르겠습니다.

상태, event_type, 날짜 순으로 정렬해야합니다.

내 배열은 다음과 같습니다.

    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



답변

당신은 필요합니다 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);

PHP 5.5.0부터 :

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

$mylist 현재 :

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


답변

으로 할 수 있습니다 usort. $cmp_function인수가 될 수있다 :

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

PHP 5.3에서 임의의 수의 필드에 대해 클로저를 사용하여 비교 함수를 만들 수 있습니다.

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

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


답변

PHP7은 우주선 연산자 (<=> “결합 비교 연산자”또는 “3 방향 비교 연산자”라고 )를 .

리소스 : https://wiki.php.net/rfc/combined-comparison-operator

여러 열을 기준으로 정렬하는 것은 연산자의 양쪽에 균형 / 관계형 배열을 작성하는 것처럼 간단합니다. 간단합니다!

uasort()원래 색인을 보존 할 필요가 없기 때문에 사용 하지 않았습니다.

코드 : ( 데모 )

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

산출

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

PHP7.4 이상의 ps Arrow 구문 ( 데모 ) …

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

모든 정렬 기준 array_multisort()array_column()대한 동등한 기술은 다음 과 같습니다 . ( 데모 )

array_multisort(
    array_column($array, 'state'),
    array_column($array, 'event_type'),
    array_column($array, 'date_start'),
    $array
);


답변

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


답변

나는 아래 코드를 시도했고 성공적으로

배열 코드

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

배열 정렬 기능 호출

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

배열 정렬 기능

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

배열 역 정렬 기능

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


답변

@Stijn Leenknegt의 천재적인 코드를 개선하여 2 센트의 실용적인 기능이 있습니다.

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


답변

누군가에게 도움이 될 수도 있습니다.

// data to sort
$output = 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')
);

// multi column, multi direction order by
$body['order_by'] = array(
        array("field"=> "event_type", "order"=> "desc"),
        array("field"=> "title", "order"=> "asc"),
        array("field"=> "ID", "order"=> "asc"),
);

$output = $this->multiColumnMultiDirectionSort($body, $output);


public function multiColumnMultiDirectionSort(array $body, array $output)
{
    // get order fields and its direction in proper format
    $orderFieldDirection = [];
    if (!empty($body['order_by']) && is_array($body['order_by'])) {
        foreach ($body['order_by'] as $order) {
            $orderDirection = $order['order'] == "desc" ? SORT_DESC : SORT_ASC; // we need format that array_multisort supports
            $orderFieldDirection[$order['field']] = $orderDirection;
        }
    }

    if (!empty($orderFieldDirection)) {
        // get the list of sort columns and their data in the format that is required by array_multisort
        $amParams = [];
        $sort = [];
        foreach ($orderFieldDirection as $field => $order) {
            foreach ($output as $k => $v) {
                $sort[$field][$k] = $v[$field];
            }

            $amParams[] = $sort[$field];
            $amParams[] = $order;
            $amParams[] = SORT_REGULAR; // this is not needed, but we can keep as it might come handy in the future
        }

        $amParams[] = &$output; // very important to pass as reference
        call_user_func_array("array_multisort", $amParams);
    }

    return $output;
}