glarkou
glarkou

Reputation: 7101

Sort columns in an associative array of indexed arrays by multiple criteria

Given the following array:

$array = array(
    'note' => array('test', 'test1', 'test2', 'test3', 'test4'),
    'year' => array('2011','2010', '2012', '2009', '2010'),
    'type' => array('journal', 'conference', 'editorial', 'conference','conference'),
);

Array can be easily transposed if it is easier (using the following function):

for ($i = 0; $i < count($array['type']); $i++)
  foreach ($array as $key => $value)
    $temp[$i][$key] = $value[$i];

print_r($temp);

And I want to sort it using the following criteria:

  1. An array $sortby = ('journal', 'editorial', 'conference')
  2. After sorting in categories I would like to sort by year DESC for every category.

Desired result:

Array
(
[note] => Array
    (
        [0] => test
        [1] => test2
        [2] => test1
        [3] => test4
        [4] => test3
    )

[year] => Array
    (
        [0] => 2011
        [1] => 2012
        [2] => 2010
        [3] => 2010
        [4] => 2009
    )

[type] => Array
    (
        [0] => journal
        [1] => editorial
        [2] => conference
        [3] => conference
        [4] => conference
    )

)

Upvotes: 0

Views: 519

Answers (2)

Lawrence Cherone
Lawrence Cherone

Reputation: 46602

If you transpose your input array, then you'll be able to sort by column at a time.

$Array = array(
    array('note' => 'test1', 'year' => '2011', 'type' => 'journal'),
    array('note' => 'test2', 'year' => '2012', 'type' => 'editorial'),
    array('note' => 'test3', 'year' => '2012', 'type' => 'conference'),
    array('note' => 'test4', 'year' => '2012', 'type' => 'conference'),
    array('note' => 'test5', 'year' => '2012', 'type' => 'conference')
);

Let's sort them by year value.

function array_sort_by_column(&$arr, $col, $dir = SORT_DESC) {
    $sort_col = array();
    foreach ($arr as $key=> $row) {
        $sort_col[$key] = $row[$col];
    }
    return array_multisort($sort_col, $dir, $arr);
}

array_sort_by_column($Array, 'year');
print_r($Array);

Output:

Array
(
    [0] => Array
        (
            [note] => test2
            [year] => 2012
            [type] => editorial
        )

    [1] => Array
        (
            [note] => test3
            [year] => 2012
            [type] => conference
        )

    [2] => Array
        (
            [note] => test4
            [year] => 2012
            [type] => conference
        )

    [3] => Array
        (
            [note] => test5
            [year] => 2012
            [type] => conference
        )

    [4] => Array
        (
            [note] => test1
            [year] => 2011
            [type] => journal
        )

)

Sort them by note value.

array_sort_by_column($Array, 'note');
print_r($Array);

Output:

Array
(
    [0] => Array
        (
            [note] => test5
            [year] => 2012
            [type] => conference
        )

    [1] => Array
        (
            [note] => test4
            [year] => 2012
            [type] => conference
        )

    [2] => Array
        (
            [note] => test3
            [year] => 2012
            [type] => conference
        )

    [3] => Array
        (
            [note] => test2
            [year] => 2012
            [type] => editorial
        )

    [4] => Array
        (
            [note] => test1
            [year] => 2011
            [type] => journal
        )

)

Sort by type value.

array_sort_by_column($Array, 'type');
print_r($Array);

Output:

Array
(
    [0] => Array
        (
            [note] => test1
            [year] => 2011
            [type] => journal
        )

    [1] => Array
        (
            [note] => test2
            [year] => 2012
            [type] => editorial
        )

    [2] => Array
        (
            [note] => test3
            [year] => 2012
            [type] => conference
        )

    [3] => Array
        (
            [note] => test4
            [year] => 2012
            [type] => conference
        )

    [4] => Array
        (
            [note] => test5
            [year] => 2012
            [type] => conference
        )

)

Upvotes: 2

mickmackusa
mickmackusa

Reputation: 47894

Use a single array_multisort() call. Write your rules as leading parameters, then write an subarrays that have not been passed in in their original (reference-able) form. The below executes the sorting process as:

  • sort by type priority ASC, then
  • sort by year DESC, then
  • sort by note ASC, then
  • sort by type ASC

The last two patameters are "coming along for the ride" -- they are mentioned so that they are mutated in accordance with earlier parameter sorting. Demo

$array = [
    'note' => ['test', 'test1', 'test2', 'test3', 'test4'],
    'year' => ['2011', '2010', '2012', '2009', '2010'],
    'type' => ['journal', 'conference', 'editorial', 'conference', 'conference'],
];
$priorities = array_flip(['journal', 'editorial', 'conference']);

array_multisort(
    array_map(fn($t) => $priorities[$t] ?? PHP_INT_MAX, $array['type']),
    $array['year'],
    SORT_DESC,
    $array['note'],
    $array['type']
);
var_export($array);

Upvotes: 0

Related Questions