James
James

Reputation: 67

PHP Sort a complex multi-dimensional array by value

I have a multi-dimensional array that generates an HTML table.

Data in array:

Array
(
    [header] => Array
        (
            [1] => Array
                (
                    [0] => Array
                        (
                            [col_pos] => 1
                            [sortable] => 1
                            [content] => Compare
                            [sort_value] => 
                            [ct_help] => Compare help text..
                        )

                    [1] => Array
                        (
                            [col_pos] => 2
                            [sortable] => 1
                            [content] => Product
                            [sort_value] => 
                            [ct_help] => Product help text..
                        )

                    [2] => Array
                        (
                            [col_pos] => 3
                            [sortable] => 1
                            [content] => Type of Cover
                            [sort_value] => 
                            [ct_help] => Type of cover help text..
                        )

                    [3] => Array
                        (
                            [col_pos] => 4
                            [sortable] => 1
                            [content] => Roadside Assistance
                            [sort_value] => 
                            [ct_help] => Roadside assistance help text...
                        )

                    [4] => Array
                        (
                            [col_pos] => 5
                            [sortable] => 1
                            [content] => Nationwhide Recovery
                            [sort_value] => 
                            [ct_help] => Nationwide Recover help text...
                        )

                    [5] => Array
                        (
                            [col_pos] => 9
                            [sortable] => 1
                            [content] => Price
                            [sort_value] => 
                            [ct_help] => Price help text...
                        )

                    [6] => Array
                        (
                            [col_pos] => 10
                            [sortable] => 1
                            [content] => 
                            [sort_value] => 
                            [ct_help] => 
                        )

                )

        )

    [row] => Array
        (
            [2] => Array
                (
                    [0] => Array
                        (
                            [col_pos] => 1
                            [sortable] => 0
                            [content] => Logo
                            [sort_value] => 
                            [ct_help] => 
                        )

                    [1] => Array
                        (
                            [col_pos] => 2
                            [sortable] => 0
                            [content] => Product cover 2
                            [sort_value] => 2
                            [ct_help] => 
                        )

                    [2] => Array
                        (
                            [col_pos] => 3
                            [sortable] => 0
                            [content] => Vehicle & Personal 2
                            [sort_value] => 2
                            [ct_help] => 
                        )

                    [3] => Array
                        (
                            [col_pos] => 4
                            [sortable] => 0
                            [content] => <b>Yes</b>
                            [sort_value] => 1
                            [ct_help] => 
                        )

                    [4] => Array
                        (
                            [col_pos] => 5
                            [sortable] => 0
                            [content] => No
                            [sort_value] => 0
                            [ct_help] => 
                        )

                    [5] => Array
                        (
                            [col_pos] => 9
                            [sortable] => 0
                            [content] => from 75 GBP
                            [sort_value] => 75
                            [ct_help] => 
                        )

                    [6] => Array
                        (
                            [col_pos] => 10
                            [sortable] => 0
                            [content] => <a href="#2">Visit site ></a>
                            [sort_value] => 
                            [ct_help] => 
                        )

                )

            [3] => Array
                (
                    [0] => Array
                        (
                            [col_pos] => 1
                            [sortable] => 0
                            [content] => Logo
                            [sort_value] => 
                            [ct_help] => 
                        )

                    [1] => Array
                        (
                            [col_pos] => 2
                            [sortable] => 0
                            [content] => Product cover 3
                            [sort_value] => 3
                            [ct_help] => 
                        )

                    [2] => Array
                        (
                            [col_pos] => 3
                            [sortable] => 0
                            [content] => Vehicle & Personal 3
                            [sort_value] => 3
                            [ct_help] => 
                        )

                    [3] => Array
                        (
                            [col_pos] => 4
                            [sortable] => 0
                            [content] => No
                            [sort_value] => 0
                            [ct_help] => 
                        )

                    [4] => Array
                        (
                            [col_pos] => 5
                            [sortable] => 0
                            [content] => <b>Yes</b>
                            [sort_value] => 1
                            [ct_help] => 
                        )

                    [5] => Array
                        (
                            [col_pos] => 9
                            [sortable] => 0
                            [content] => from 73 GBP
                            [sort_value] => 73
                            [ct_help] => 
                        )

                    [6] => Array
                        (
                            [col_pos] => 10
                            [sortable] => 0
                            [content] => <a href="#3">Visit site ></a>
                            [sort_value] => 
                            [ct_help] => 
                        )

                )

            [4] => Array
                (
                    [0] => Array
                        (
                            [col_pos] => 1
                            [sortable] => 0
                            [content] => Logo
                            [sort_value] => 
                            [ct_help] => 
                        )

                    [1] => Array
                        (
                            [col_pos] => 2
                            [sortable] => 0
                            [content] => Product cover 4
                            [sort_value] => 4
                            [ct_help] => 
                        )

                    [2] => Array
                        (
                            [col_pos] => 3
                            [sortable] => 0
                            [content] => Vehicle & Personal 4
                            [sort_value] => 4
                            [ct_help] => 
                        )

                    [3] => Array
                        (
                            [col_pos] => 4
                            [sortable] => 0
                            [content] => <b>Yes</b>
                            [sort_value] => 1
                            [ct_help] => 
                        )

                    [4] => Array
                        (
                            [col_pos] => 5
                            [sortable] => 0
                            [content] => <b>Yes</b>
                            [sort_value] => 1
                            [ct_help] => 
                        )

                    [5] => Array
                        (
                            [col_pos] => 9
                            [sortable] => 0
                            [content] => from 84 GBP
                            [sort_value] => 84
                            [ct_help] => 
                        )

                    [6] => Array
                        (
                            [col_pos] => 10
                            [sortable] => 0
                            [content] => <a href="#4">Visit site ></a>
                            [sort_value] => 
                            [ct_help] => 
                        )

                )

            [5] => Array
                (
                    [0] => Array
                        (
                            [col_pos] => 1
                            [sortable] => 0
                            [content] => Logo
                            [sort_value] => 
                            [ct_help] => 
                        )

                    [1] => Array
                        (
                            [col_pos] => 2
                            [sortable] => 0
                            [content] => Product cover 5
                            [sort_value] => 5
                            [ct_help] => 
                        )

                    [2] => Array
                        (
                            [col_pos] => 3
                            [sortable] => 0
                            [content] => Vehicle & Personal 5
                            [sort_value] => 5
                            [ct_help] => 
                        )

                    [3] => Array
                        (
                            [col_pos] => 4
                            [sortable] => 0
                            [content] => No
                            [sort_value] => 0
                            [ct_help] => 
                        )

                    [4] => Array
                        (
                            [col_pos] => 5
                            [sortable] => 0
                            [content] => <b>Yes</b>
                            [sort_value] => 1
                            [ct_help] => 
                        )

                    [5] => Array
                        (
                            [col_pos] => 9
                            [sortable] => 0
                            [content] => from 96 GBP
                            [sort_value] => 96
                            [ct_help] => 
                        )

                    [6] => Array
                        (
                            [col_pos] => 10
                            [sortable] => 0
                            [content] => <a href="#5">Visit site ></a>
                            [sort_value] => 
                            [ct_help] => 
                        )

                )

        )

)

HTML Table renders like so:

+---------+-----------------+----------------------+----------+------------+--------------+--------------+
| Compare |     Product     |    Type of Cover     | Roadside | Nationwide |    Price     |              |
+---------+-----------------+----------------------+----------+------------+--------------+--------------+
| Logo    | Product Cover 2 | Vehicle & Personal 2 | Yes      | No         | from £75 GBP | Visit site > |
| Logo    | Product Cover 3 | Vehicle & Personal 3 | No       | Yes        | from £73 GBP | Visit site > |
| Logo    | Product Cover 4 | Vehicle & Personal 4 | Yes      | Yes        | from £84 GBP | Visit site > |
| Logo    | Product Cover 5 | Vehicle & Personal 5 | No       | No         | from £96 GBP | Visit site > |
+---------+-----------------+----------------------+----------+------------+--------------+--------------+

Now I want to be able to sort by "price" but as you can see in the array the 'content' key for the price cell is a string and we need to sort it by the 'sort_value' key. Other sortable columns like 'Roadside' or 'Nationwide' should be sortable too by their 'sort_value' key.

I have tried different combinations of array_multisort or usort but was not successful.

Any help on this would be much appreciated. If you have questions, please feel free to ask.

Thanks in advance.

Upvotes: 0

Views: 43

Answers (1)

Nick
Nick

Reputation: 147176

Here's a function that will sort your list the way you want it to. It first searches for the key of the field to sort on in the headers part of the array, then sorts the row part based on the sortable values for that key:

function sort_list($list, $field, $ascending = true) {
    $headers = array_values($list['header'])[0];
    if (($key = array_search($field, array_column($headers, 'content'))) === false || $headers[$key]['sortable'] == 0) {
        // can't find field or field is not sortable, do nothing
        return $list;
    }
    usort($list['row'], function ($a, $b) use ($key, $ascending) {
        return $ascending ? $a[$key]['sort_value'] <=> $b[$key]['sort_value'] : $b[$key]['sort_value'] <=> $a[$key]['sort_value'];
    });
    return $list;
}

Sample usage:

sort_list($data, 'Price');

Demo on 3v4l.org

Upvotes: 1

Related Questions