Multidimensional arrays and functionality performed on arrays

Unit: 12 of 19

In the previous lesson, we used more strings that contain a list of key/value pairs. We have seen that using associative strings can be much more practical than using numeric strings and vice versa. I also mentioned multidimensional arrays. We could say that such strings are, in fact, strings of strings, because their elements are new strings, i.e. substrings. There can be multiple substrings. If a string has only one substring, then we speak of a two-dimensional string. If that substring has its own substring, then we say that it is a three-dimensional string, etc. Most people have a hard time dealing with strings when they have three- or four-dimensional strings.

In the continuation of the lesson, we will approach associative strings in more detail, and then also multidimensional strings.

String pairs (associative string)

In addition to the strings in which each member has its own position, determined by the index, which represents a numerical value, a string can also be created in which the values ​​are linked to certain keys in this string, respectively strings that are associated with a value.

For example, if we wanted to create a string of countries, and to each country we associate its capital, we would use this type of string. Thus, countries can be keys, while values ​​can be cities.

Creating the string would look like this:

1
$arr = array("Romania"=>"Bucharest", "France"=>"Paris", "England"=>"London");

where the values ​​to the left of the => sign represent the key , and the value to the right represents the value of that key.

Getting the value of a particular key in such a string is quite simple:

1
echo $arr["Romania"];

This line of code will output the value for the key »Romania«, which in this case is Bucharest.

The multidimensional string

In addition to one-dimensional strings, which we studied in the previous lesson, PHP can also recognize so-called multidimensional strings. These strings are very useful for working with data in array or table form.

For example, suppose we want to store some data in the form of a table, so that the table contains the following columns: ID, Surname, Surname, CNP.

E.g:

ID First name Name CNP
1 John Miller 1111111111111
2 Peter Andersen 2222222222222
3 Well Newman 3333333333333

 

In this case, we will be able to use a two-dimensional string:

1
2
3
4
$arr = array();
    $arr[0] = array(1, "John", "Miller", "1111111111111");
    $arr[1] = array(2, "Peter", "Andersen", "2222222222222");
    $arr[2] = array(3, "Ana", "Newman", "3333333333333");

We could have completed this string differently during initialization:

1
2
3
4
5
$arr = array(
    array( 1, "John", "Miller", "1111111111111" ),
    array( 2, "Peter", "Andersen", "2222222222222" ),
    array( 3, "Ana", "Newman", "3333333333333")
);

Observing this structure, we could very easily reach any element in the string. For example, if we want to get the surname Andersen, we could follow this path:

1
echo $arr[1][2];

Now, on the page we would have the result: Andersen

Also, all the names in this structure could be passed with the help of the loop:

1
2
3
for($i=0; $i<count($arr); $i++){
    echo $arr[$i][1]."<br>";
}

…or if we want to publish all the data in the table:

1
2
3
for($i=0; $i<count($arr); $i++){
    echo $arr[$i][0] . " " . $arr[$i][1] . " " . $arr[$i][2] . " " . $arr[$i][3] ."<br>";
}

 

These solutions are practical when we have a fixed number of members of the substring (in this case, it is the columns of our table), but not if we want to manage certain dynamic data, the quantity of which we do not know in advance. For example, a program that manages images and where the user can upload an image in any format. In this case, we should work with strings of unknown size and should use a different method to iterate through its members.

For example, an array with the values:

1 2 3 4
5 6 7 8
9 0 1 2

In string form, this matrix would look like this:

1
2
3
4
5
6
7
<?php
$arr = array(
array( 1, 2, 3, 4 ),
array( 5, 6, 7, 8 ),
array( 9, 0, 1, 2 )
);
?>

and it would be easy to iterate through it, derived from the example above.

But, let’s imagine that, instead of this known structure, we get a variable $arr, whose data is unknown to us (we only know that it is a two-dimensional string); in this case, we should resort to a different technique:

1
2
3
4
5
for($sp=0; $sp<count($arr); $sp++){
    for($up=0; $up<count($arr[$sp]); $up++)
        echo $arr[$sp][$up] . " ";
            echo "<br>";
}

However, even this is not enough to save the data about an image, because an image has, at each coordinate, a certain set of data (about color). Since color often consists of three values ​​(if it’s the RGB model), we’ll need to create another three-member string for each point.

Of course, there are other, more efficient methods for managing this type of data (for example, objects).

To fulfill the mentioned request, we need to change the code a bit. First, suppose that the string obtained by parsing an image looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$arr = array(
            array(
                array(0,0,0),
                array(255,255,255),
                array(0,0,0),
                array(255,255,255)
            ),
            array(
                array(255,255,255),
                array(0,0,0),
                array(255,255,255),
                array(0,0,0)
            ),
            array(
                array(0,0,0),
                array(255,255,255),
                array(0,0,0),
                array(255,255,255)
            )
);

so that each substring of the main string is a row, and each substring in a row is a dot.

To iterate through the serialized data like this, we could use the following code:

1
2
3
4
5
6
7
for( $sp = 0; $sp < sizeof( $arr ); $sp++ )
    {
    for( $up = 0; $up < sizeof( $arr[ $sp ]); $up++ )
        for( $up1 = 0; $up1 < sizeof( $arr[ $sp ][ $up ]); $up1++ )
            echo $arr[ $sp ][ $up ][ $up1 ] . " ";
        echo "<br>";
    }

An advantage that can be used when working with multidimensional arrays is the foreach loop . This loop takes care of the size and positions of the string members during iteration, which is why it’s great for simple operations. On the other hand, this approach reduces the control over the string members. The foreach loop will be described in more detail in one of the following lessons.

When using the foreach loop, traversing the string above would look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$arr = array(
array(array(0,0,0),array(255,255,255),array(0,0,0),array(255,255,255)),
array(array(255,255,255),array(0,0,0),array(255,255,255),array(0,0,0)),
array(array(0,0,0),array(255,255,255),array(0,0,0),array(255,255,255))
);
foreach($arr as $row){
    foreach($row as $point){
        foreach($point as $color){
            echo $color . " ";
        }
    }
echo "<br>";
}

 

For what type of data is the use of multidimensional arrays appropriate?

Advanced functions that can be applied to strings

To display the members of the string, without moving through the individual members (as in the previous examples), the function print_r can be used. This function decomposes the string, displaying its keys or index numbers and the values ​​below them.

E.g:

1
2
$arr = array("Romania"=>"Bucharest", "France"=>"Paris", "England"=>"London");
print_r($arr);

will have the result:

1
Array ( [Romania] => Bucharest [France] => Paris [England] => London )

Using this function can be very useful during application development, but it is not recommended to use it in production, the string elements should be parsed on output in the most convenient way (this is most often the way to parse through a loop type).

Array_walk()

The array_walk() function is used to move the array elements by the specified function. The keys and values ​​of the string element represent the arguments of the function. If the changes, which the function causes on keys and values, we want to save them immediately in the same string, then we can use the & operator to point to the memory address.

Example:

1
2
3
4
5
6
7
$arr = array("Romania"=>"Bucharest", "France"=>"Paris", "England"=>"London");
array_walk($arr, 'arrFunc', ' is the capital city of the state whose name is ');
function arrFunc($value, $ key, $p){
    echo $ value . $p . $ key . ".<br>";
}

The function goes through all the elements of the string $arr and calls the arrFunc function on each one. The function accepts the key and the value of the element, but also the additional parameter in the form of a string, which has the value “is capital city of state which name is”. After the function processes the element, it moves on to the next element, so the output on the page is:

Bucharest is the capital city of the state whose name is Romania.
Paris is the capital city of the state whose name is France.
London is the capital city of the state whose name is England.

Array_fill()

If we want to form a string populated with a static value, we can use this function, where the first parameter is the starting index of the string, the second parameter is the number of inserted members, and the last parameter is the value to insert:

1
2
$x = array_fill( 0, 10, "hello" );
print_r( $x );

This code returns:

1
Array ( [0] => hello [1] => hello [2] => hello [3] => hello [4] => hello [5] => hello [6] => hello [7] => hello [8] => hello [9] => hello )

In this way, several strings can be copied into another string, or a multidimensional string can be created, because this function can also receive a string as a parameter. 

Array_flip()

Change the positions of keys and values. If the string consists of keys and values, this function will replace the keys and values, and if the string has no keys but only indices, this function will replace the member indices with the member values.

The code:

1
2
3
$arr = array("Romania" => "Bucharest", "France" => "Paris", "England" => "London");
$x = array_flip($arr);
print_r($x);

issue:

1
Array ( [Bucharest] => Romania [Paris] => France [London] => England )


Array_pop()

To understand this function and the next one, we must first understand two ways of accessing any collection of data in programming: FIFO and LIFO . FIFO is short for First In First Out and assumes that the element that accessed the data collection first leaves it first. While LIFO , Last In First Out (last in, first out), assumes that the last element that accessed the collection, leaves it first.

Often, these two approaches are compared to the two situations: the office at work and the queue at the post office.

  • Office at work (LIFO):

    If we put a pile of papers on the table, the last paper put on the table will be at the top of the pile and will be taken first.

  • First-in, first-out (FIFO):

    The person who came last in line will be the last to arrive at the counter.

Things work the same way in programming: stack (office) and queue (mail). Usually (in programming, in particular), these two popular types of data collection are associated with two functions. For stack, these are pop and push , and for queue –  dequeue and enqueue.

Array_pop() will extract and delete the last element from the array, but place a marker at its previous position.

So the following code will output Washington as a result:

1
2
$arr = array( "Bucharest", "Paris", "London", "Washington" );
echo array_pop( $arr );

but the following code will issue: WashingtonLondonParisBucharest

1
2
3
4
5
$arr = array( "Bucharest", "Paris", "London", "Washington" );
echo array_pop( $arr );
echo array_pop( $arr );
echo array_pop( $arr );
echo array_pop( $arr );

To add an element to the array according to the same principle, we will use the function: array_push().

Array_push()

1
2
3
$arr = array("Bucharest", "Paris", "London");
array_push( $arr, "Washington" );
print_r( $arr );

The result is:

1
Array ( [0] => Bucharest [1] => Paris [2] => London [3] => Washington )

This function produces an identical result to the one we would get if we entered the value directly, through the command:

1
$arr[] = "Washington";

However, using the array_push() function produces a slightly faster result, as it is more efficient in working with larger amounts of data.

list()

Assigns string values ​​to the passed list of variables.

1
2
3
$capitals = array("Bucharest", "Paris", "London");
list($Romania, $France, $England) = $capitals;
echo $France;

This approach is suitable for a small amount of static data.

The output of the code will be:

Paris

Exercise 1

The following string is given:

1
$table = array("format" => array(7, 7),"positions" => array(array(3, 5),array(1, 4),array(4, 6),array(3, 7)));

Using the loop, step through the corresponding strings so as to create a table of the dimensions mentioned in the formed substring, the table string.

Display a table so that all free fields are shown as 0, and all fields that are in the positions substring of the table string are shown as X. For the given string, the output should look like this:

0000000
0000000
0000000
X000000
00X0000
000X000
00X0000

Solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$table = array("format" => array(7, 7),"positions" => array(array(3, 5),array(1, 4),array(4, 6),array(3, 7)));
for($fh=1; $fh<=$table['format'][1]; $fh++){
    for($fw=1; $fw<=$table['format'][0]; $fw++){
        $pointExists = false;
        foreach($table['positions'] as $pos){
            if($pos[0] == $fh && $pos[1] == $fw){
                echo 'X';
                $pointExists = true;
            }
        }
        if(!$pointExists) echo '0';
    }
    echo '<br>';
}
?>

Information about the table to be created is found in the $table string. This string has two elements. The first element is:

1
"format" => array(7, 7)

with which the table dimensions are defined, while the second element is:

1
"positions" => array(array(3, 5),array(1, 4),array(4, 6),array(3, 7))

and with it the points where the X sign will be presented are defined.

To generate the table on the page, we must use two for loops, to resolve the presentation of the columns and rows:

1
2
for($fh=1; $fh<=$table['format'][1]; $fh++){
    for($fw=1; $fw<=$table['format'][0]; $fw++){

The variable $pointExists at the beginning of the iteration has the boolean value false, which can change later if there is an overlap with the defined points and loop counters.

Then, we check just such an overlap through the foreach loop:

1
2
3
4
5
6
foreach($table['positions'] as $pos){
            if($pos[0] == $fw && $pos[1] == $fh){
                echo 'X';
                $pointExists = true;
            }
        }

If the overlap is confirmed, the $pointExists variable changes its value to true. This is important because only if the overlap point does not exist do we want to write to the page “0”.

Exercise 2

The following string is given:

1
$population = array("London" => 7556900,"Bucharest" => 1500000,"New York" => 8406000, "Paris" => 11836970);

Create a population count program to create a primitive graph that displays the number of inhabitants on a scale of 1 to 10 as a percentage. A percentage will be formed so that the city with the largest population is 100%.

In the diagram, the parts included in the scale should be shown with the # sign, while the parts that do not cover the value should not be shown (these signs are arbitrary).

At the bottom of the list, the names of the cities should appear vertically.

The final layout of the example is as follows:


Solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
$population = array("London" => 7556900, "Bucharest" => 1500000, "New York" => 8406000, "Paris" => 11836970);
$max = 0;
$longestCityName = 0;
foreach($population as $k => $v)
    {
    if($v > $max)
        $max = $v;
    if(strlen( $k ) > $longestCityName)
        $longestCityName = strlen( $k );
    }    
$percent = 100 / $max;
for($i = 10; $i >= 0; $i--)
{
foreach($population as $k => $v)
    {
        $currentPercent = ceil(($percent * $v)/10);
             if($currentPercent >= $i)
                        echo "#" . "   ";
             else
                        echo "<span style='color:white;'>#</span>" . "   ";
    }
echo "<br>";
}
for($i = 0; $i < $longestCityName; $i++)
{
    foreach($population as $k => $v)
        {
            if(strlen( $k ) > $i)
            {
                $cityArr = str_split( $k );
                echo $cityArr[ $i ] . "   ";
            }
            else
                echo "    ";
        }
        echo "<br>";
}
?>

When we look at the requirements of the problem and the code that presents its solution, we notice that apart from the ceil() function, there are no parts of the syntax that we have not already encountered and addressed. Therefore, here we will deal with the ceil() function. This function rounds the given number to the nearest integer value, if necessary. If we assign the whole number to the function, instead of the call it returns exactly this number (unmodified). To round the number to the first lower numerical value, we use the floor() function.

 

Is it possible to create a string where the values ​​are bound to certain keys in that string?