Tuesday 14 August 2018

Multidimensional Arrays in PHP

A multidimensional array is an array with elements that are arrays themselves. In PHP, array elements can contain a mix of data types, and they can have string keys or numeric keys. We provide several examples of multidimensional arrays on this page. Our first example has string keys at the top level and numeric keys on sub-array elements:
$food = [
    'fruits' => ['apple', 'raspberry', 'pear', 'banana'],
    'vegetables' => ['peas', 'carrots', 'cabbage'],
    'grains' => ['wheat', 'rice', 'oats']
];

How to Access Elements in Multidimensional Arrays

Keys in square brackets are used to access array elements. The first set of square brackets refers to the top-level elements in a multidimensional array. Each subsequent set of square brackets refers to the next level down. The following demonstrates how to access the third element in the 'vegetables' sub-array of the $food array defined above:
echo $food['vegetables'][2]; // cabbage
The following demonstrate how to change the value of the first element in the 'vegetables'sub-array:
$food['vegetables'][0] = 'green beans';

Array Functions with Multidimensional Arrays

There are a few array functions that are specifically designed for multidimensional arrays. But you can also apply regular array functions to the outer array or sub-arrays of multidimensional arrays. For example, the array_push function can be used to add elements to a sub-array as follows:
// add 2 elements to vegetables sub-array of $food array defined above
array_push($food['vegetables'], 'kale', 'chard');
print_r($food);
/* print_r output (as seen in page source view):
Array
(
    [fruits] => Array
        (
            [0] => apple
            [1] => raspberry
            [2] => pear
            [3] => banana
        )

    [vegetables] => Array
        (
            [0] => green beans
            [1] => carrots
            [2] => cabbage
            [3] => kale
            [4] => chard
        )

    [grains] => Array
        (
            [0] => wheat
            [1] => rice
            [2] => oats
        )

) */
Our next example demonstrates passing a multidimensional array to the array_shift function to remove its first element, which is a sub-array:
// remove first element from $food array defined above
array_shift($food);
print_r($food);
/* Array
(
    [vegetables] => Array
        (
            [0] => green beans
            [1] => carrots
            [2] => cabbage
            [3] => kale
            [4] => chard
        )

    [grains] => Array
        (
            [0] => wheat
            [1] => rice
            [2] => oats
        )

) */

The array_column Function

PHP's array_column function is designed specifically for multidimensional arrays. Pass array_column a multidimensional array and a key (numeric or string), and it will return an array consisting of those values from each sub-array.
We use a multidimensional array of products to demonstrate. The numerically indexed sub-arrays hold the name of the product in the second array element. To return an array of product names we pass the $products array and 1 to array_column:
$products = [
    // label, name, unit price
    ['choc_cake', 'Chocolate Cake', 15],
    ['carrot_cake', 'Carrot Cake', 12],
    ['cheese_cake', 'Cheese Cake', 20],
    ['banana_bread', 'Banana Bread', 14]
];

$ar = array_column($products, 1);
print_r($ar);
/* Array
(
    [0] => Chocolate Cake
    [1] => Carrot Cake
    [2] => Cheese Cake
    [3] => Banana Bread
) */
The array_column function supports an optional third argument to specify a column to be used as the key for each element in the returned array. To demonstrate we use a products array whose sub-arrays are associative: $products2. We pass this array along with 'name' and 'label' to array_column to return an array of product names with labels as keys:
$products2 = [
    ['label' => 'choc_cake', 'name' => 'Chocolate Cake', 'price' => 15],
    ['label' => 'carrot_cake', 'name' => 'Carrot Cake', 'price' => 12],
    ['label' => 'cheese_cake', 'name' => 'Cheese Cake', 'price' => 20],
    ['label' => 'banana_bread', 'name' => 'Banana Bread', 'price' => 14]
];

$ar = array_column($products2, 'name', 'label');
print_r($ar);
/* Array
(
    [choc_cake] => Chocolate Cake
    [carrot_cake] => Carrot Cake
    [cheese_cake] => Cheese Cake
    [banana_bread] => Banana Bread
) */

Traversing Multidimensional Arrays

We have covered array functions and language constructs used to traverse arrays, such as foreacharray_walk, and others. Below we show how some of these can be applied to multidimensional arrays. But first we present PHP's array_walk_recursive function for traversing multidimensional arrays.

array_walk_recursive

The array_walk_recursive function iterates over the elements of a multidimensional array applying the callback function passed as the second argument to each element of sub-arrays. Only elements that are not themselves arrays are passed to the callback function.
We apply array_walk_recursive to a multi-level array to demonstrate. The inline callback function applies the ucwords string function to each value passed:
$food = [
    'meat' => ['chicken', 'fish'],
    'vegetables' => [
        'leafy' => ['collard greens', 'kale', 'chard', 'spinach', 'lettuce'],
        'root' => ['radish', 'turnip', 'potato', 'beet'],
        'other' => ['brocolli', 'green beans', 'corn', 'tomatoes']
    ],
    'grains' => ['wheat', 'rice', 'oats'],
];

// use & (reference sign) to change values in array
array_walk_recursive($food, function (&$val) { $val = ucwords($val); } );
print_r($food);
/* Array
(
    [meat] => Array
        (
            [0] => Chicken
            [1] => Fish
        )

    [vegetables] => Array
        (
            [leafy] => Array
                (
                    [0] => Collard Greens
                    [1] => Kale
                    [2] => Chard
                    [3] => Spinach
                    [4] => Lettuce
                )

            [root] => Array
                (
                    [0] => Radish
                    [1] => Turnip
                    [2] => Potato
                    [3] => Beet
                )

            [other] => Array
                (
                    [0] => Brocolli
                    [1] => Green Beans
                    [2] => Corn
                    [3] => Tomatoes
                )

        )

    [grains] => Array
        (
            [0] => Wheat
            [1] => Rice
            [2] => Oats
        )

) */
Our example passes the value as a reference to the callback function in order to modify the array elements.
The array_walk_recursive function passes the current array element's key as the second argument to the callback function. We demonstrate its use in the following example:
$products2 = [
    ['label' => 'choc_cake', 'name' => 'Chocolate Cake', 'price' => 15],
    ['label' => 'carrot_cake', 'name' => 'Carrot Cake', 'price' => 12],
    ['label' => 'cheese_cake', 'name' => 'Cheese Cake', 'price' => 20],
    ['label' => 'banana_bread', 'name' => 'Banana Bread', 'price' => 14]
];

array_walk_recursive($products2, function (&$val, $key) { 
    if ( $key == 'price') {
        $val = number_format($val * 1.1, 2);
    }
} );

print_r($products2);
/* Array
(
    [0] => Array
        (
            [label] => choc_cake
            [name] => Chocolate Cake
            [price] => 16.50
        )

    [1] => Array
        (
            [label] => carrot_cake
            [name] => Carrot Cake
            [price] => 13.20
        )

    [2] => Array
        (
            [label] => cheese_cake
            [name] => Cheese Cake
            [price] => 22.00
        )

    [3] => Array
        (
            [label] => banana_bread
            [name] => Banana Bread
            [price] => 15.40
        )

) */
Our callback function inspects the key. If it is 'price', the value is modified, increasing the price of each product by 10 percent.

Using foreach to Traverse Multidimensional Arrays

There are any number of ways that you could use foreach and for loops to iterate over multidimensional arrays. We demonstrate just a few of these possibilities here.
Our first example combines foreach with list to display values from each sub-array:
$products = [
    // label, name, unit price
    ['choc_cake', 'Chocolate Cake', 15],
    ['carrot_cake', 'Carrot Cake', 12],
    ['cheese_cake', 'Cheese Cake', 20],
    ['banana_bread', 'Banana Bread', 14]
];

foreach($products as $product) {
    //list($label, $name, $price) = $product;
    list(, $name, $price) = $product; // to discard label
    echo "$name is \$$price.<br />";
}
/* 
Chocolate Cake is $15.
Carrot Cake is $12.
Cheese Cake is $20.
Banana Bread is $14. 
*/
The next example produces the same result by applying extract to associative sub-arrays:
$products2 = [
    ['label' => 'choc_cake', 'name' => 'Chocolate Cake', 'price' => 15],
    ['label' => 'carrot_cake', 'name' => 'Carrot Cake', 'price' => 12],
    ['label' => 'cheese_cake', 'name' => 'Cheese Cake', 'price' => 20],
    ['label' => 'banana_bread', 'name' => 'Banana Bread', 'price' => 14]
];

foreach($products2 as $product) {
    extract($product);
    echo "$name is \$$price.<br />";
}
// (same result as above example)
The following example modifies the array, achieving the same result as array_walk_recursivein an earlier example:
$products = [
    ['choc_cake', 'Chocolate Cake', 15],
    ['carrot_cake', 'Carrot Cake', 12],
    ['cheese_cake', 'Cheese Cake', 20],
    ['banana_bread', 'Banana Bread', 14]
];

// use & (reference sign) to change values in array
foreach($products as &$product) {
    $product[2] *= 1.1; // 
}
print_r($products);
/* Array
(
    [0] => Array
        (
            [0] => choc_cake
            [1] => Chocolate Cake
            [2] => 16.5
        )

    [1] => Array
        (
            [0] => carrot_cake
            [1] => Carrot Cake
            [2] => 13.2
        )

    [2] => Array
        (
            [0] => cheese_cake
            [1] => Cheese Cake
            [2] => 22
        )

    [3] => Array
        (
            [0] => banana_bread
            [1] => Banana Bread
            [2] => 15.4
        )

) */
There are many more ways that the array iteration functions and constructs could be combined for use with multidimensional arrays.

0 comments:

Post a Comment