This is another practical session, so please continue to type the examples you see in the manual.
The general subject is tables, and the first topic in connection with tables is how to set them up. That's a topic that could involve you in a lot of keying. (Imagine typing in 50 different values to fill a modest five-row by ten-column table!) To avoid such drudgery we'll look first at two functions that will generate the numbers for you.
|col 1||col 2||col 3|
You always specify the number of rows before the number of columns, and APL fills the table row-by-row rather than column-by-column. (This may seem a trivial point, but if APL first filled column 1, then column 2 then column 3, the effect would be quite different).
The data to be put in the table can itself be in a variable. This next statement puts 12 random numbers in the range 1 to 100 into a variable called
DATA ← 12 ? 100
Now use the
⍴ function again, but specify
DATA as the right-hand argument:
4 3 ⍴ DATA 15 57 30 51 50 97 18 26 38 67 22 69
(Your numbers are unlikely to be the same!)
The next example looks doomed to failure because there are insufficient numbers on the right to fill a table of the specified dimensions. But try it anyway and see what APL does:
4 3 ⍴ 1 2 3 4 5
As you saw, when the numbers ran out, APL went back to the first number and went through them again, giving a table like this:
1 2 3 4 5 1 2 3 4 5 1 2
It follows that if you supply only one number, APL will use that to fill the whole table:
3 5 ⍴ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
On the other hand, if you supply too many numbers, APL uses what it needs to fill the table and ignores the rest:
2 3 ⍴ 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6
Try setting up some tables before you read on. Remember that you can use the
Now please set up a 3-row 3-column table called
SALES, containing the numbers shown:
SALES ← 3 3⍴20 13 8 30 43 48 3 50 21 SALES 20 13 8 30 43 48 3 50 21
SALES will automatically affect every number in the table. For example:
SALES×10 200 130 80 300 430 480 30 500 210
Suppose you now set up another table called, say,
PRICES, will you be able to do operations like
PRICES? Let's find out:
PRICES ← 2 3 ⍴ 21 2 12 47 33 1 SALES×PRICES
The attempt caused an error:
LENGTH ERROR SALES×PRICES ^
LENGTH ERROR message means that the arguments contain different numbers of elements. The problem, obviously, is that
SALES is three rows by three columns, and therefore contains nine numbers, while
PRICES is two rows by three columns, and therefore contains six numbers. How could APL know which items you want multiplied by which? Since it doesn't, it gives an error message.
Let's redefine the
SALES table so that it too contains six items:
SALES ← 3 2 ⍴ SALES
(We used the numbers already in
SALES as data. The effect of the statement is to take the first six numbers in the old
SALES table and rearrange them as three rows and two columns to form the new
PRICES, contains six numbers, let's try the multiplication again:
SALES×PRICES LENGTH ERROR SALES×PRICES ^
We're still getting an error message. If we look at both tables the problem will be apparent:
SALES 20 13 8 30 43 48 PRICES 21 2 12 47 33 1
The tables may now have the same number of items, but they're still a different 'shape'. It's impossible to know, with any certainty, which item in
SALES corresponds to which item in
We'll have to redefine
SALES again so that it has the same number of rows and columns as
SALES ← 2 3 ⍴ SALES
(Again we've used the numbers already in
SALES as data for the new version of the table.)
Now we'll check that
PRICES are the same shape (i.e. have the same number of rows and columns):
SALES 20 13 8 30 43 48 PRICES 21 2 12 47 33 1
They now match exactly in shape and size, so we can try again.
SALES×PRICES 420 26 96 1410 1419 48
Success at last! The elements in the two tables now match-up, or conform, and arithmetic involving both tables is possible. Let's check by trying another operation on them:
SALES - PRICES ¯1 11 ¯4 ¯17 10 47
That worked too. (Remember that the previous multiplication didn't change the contents of the tables.)
Incidentally, you don't have to create every table explicitly. You can create one simply by assigning a result to it. Here you're creating a table called
TOTAL ← SALES×PRICES TOTAL 420 26 96 1410 1419 48
Before you read on, practice constructing tables and doing arithmetic on them. Make use of the
⍳ functions to set the tables up. Don't forget about the
⌊ functions. They work on tables too.
You can catenate tables just as you catenated other variables in the previous session:
SALES,PRICES 20 13 8 21 2 12 30 43 48 47 33 1
The tables being catenated must have the same number of rows, but don't have to have the same number of columns.
This next example creates a two-row two-column table called
LITTLE filled with
1s, and a two-row six-column table called
MEDIUM filled with
5s. Then it catenates the tables and puts the result in
LITTLE ← 2 2 ⍴ 1 MEDIUM ← 2 6 ⍴ 5 BIG ← LITTLE,MEDIUM LITTLE 1 1 1 1 MEDIUM 5 5 5 5 5 5 5 5 5 5 5 5 BIG 1 1 5 5 5 5 5 5 1 1 5 5 5 5 5 5
Again, notice that though the catenated tables have different numbers of columns, they both have the same number of rows.
Catenation supplies one of many solutions to the problem of arithmetic being possible only on tables of equal size. Suppose you wanted to add
LITTLE+MEDIUM LENGTH ERROR LITTLE+MEDIUM ^
You can't because they're different sizes. They both have two rows, but
LITTLE has two columns while
MEDIUM has six:
LITTLE 1 1 1 1 MEDIUM 5 5 5 5 5 5 5 5 5 5 5 5
The following example shows how
LITTLE can be catenated with a table of zeroes to pad it out to the same size as
MEDIUM so that the addition can take place:
ZEROES ← 2 4 ⍴ 0 ZEROES 0 0 0 0 0 0 0 0 LITTLE ← LITTLE,ZEROES LITTLE 1 1 0 0 0 0 1 1 0 0 0 0 LITTLE+MEDIUM 6 6 5 5 5 5 6 6 5 5 5 5
The addition took place successfully. Presumably we wanted the original
LITTLE to be added on to the left-hand end of
MEDIUM. If we wanted it on the other side we should have specified (resetting
LITTLE ← 2 2⍴1 LITTLE ← ZEROES,LITTLE LITTLE+MEDIUM 5 5 5 5 6 6 5 5 5 5 6 6
It's because that kind of ambiguity exists that APL won't do arithmetic on data of unequal size.
You may be wondering how you select single elements from tables.
First set up this table (using the numbers shown rather than the
? function), then we'll select individual elements from it :
+TABLE ← 4 3 ⍴ 2 12 15 4 11 7 1 16 8 20 19 9 2 12 15 4 11 7 1 16 8 20 19 9
Remember that the table consists of four rows and three columns.
To select the
9 in the bottom row, right-most column, type:
You've used the row number <4>, and the column number <3>, to identify which element of the table you want. Before you read on, see if you can enter a statement which adds the number in row 3 column 3, to the number in row 4 column 2. Make sure you use the square brackets and separate the row number from the column number with a semicolon.
You should have entered:
TABLE[3;3] + TABLE[4;2] 27
Now see if you can replace the number in row 3, column 2 with the result of adding the numbers in row 1, column 2, and row 2, column 2. Here's the table again with the numbers marked:
2 12 15 4 11 7 1 16 8 20 19 9
That shouldn't have been difficult as long as you counted the rows and columns correctly, and remembered the semicolons. You no doubt typed:
TABLE[3;2] ← TABLE[1;2] + TABLE[2;2]
TABLE make sure that row 3, column 2 now contains the sum of rows 1 and 2 column 2:
TABLE 2 12 15 4 11 7 1 23 8 20 19 9
It's quite easy to select entire rows or columns. Here we select all three elements in row 1:
TABLE[1;1 2 3] 2 12 15
As before, the number before the semicolon denotes the row while the number, or in this case numbers, after the semicolon denote the column(s). There is, however, a shorthand way of selecting whole rows or columns. The following statement does the same as the last, that is, it selects all columns in row 1:
TABLE[1;] 2 12 15
Using the same principle, see if you can replace the numbers in column 3 with the sum of the numbers in columns 1 and 2.
(In the course of some of these operations you may be getting an error message saying that you've made an
INDEX ERROR. The process of picking elements out of a table is called 'indexing'. A mistake is therefore referred to as an 'index' error.)
To add the first two columns and put the result in column three you could have typed:
TABLE[1 2 3 4;3] ← TABLE[1 2 3 4;1] + TABLE[1 2 3 4;2] TABLE 2 12 14 4 11 15 1 23 24 20 19 39
Alternatively you could have used the shorthand way:
TABLE[;3] ← TABLE[;1] + TABLE[;2]
You can, of course, select elements from two separate tables and do arithmetic on them. If you still have the tables
PRICES in your workspace, the following statement will multiply the number in row 1 column 1 of
SALES by the number in row 2 column 3 of
SALES[1;1] × PRICES[2;3] 20
Incidentally, indexing can also be used to pick single elements out of lists. With lists, of course, only one number is needed to identify the element required:
LIST ← 8 1 90 4 LIST 1
A quick digression about dimensions is in order before we tackle the next topic. APL regards data as having dimensions.
Arrays of up to sixty three dimensions are possible in APLX, but we won't attempt to represent them!
The thought of three-dimensional data may intrigue you, but in practice it's quite mundane - as the next example will reveal. Suppose the ordinary two-dimensional table you're about to create represents the number of each of four products sold by each of six salesmen:
SALES ← 6 4⍴24?50 SALES 5 34 22 36 46 40 18 10 39 23 4 41 50 27 8 13 12 42 9 3 19 47 30 35
The salesmen are the rows, the different products are the columns:
|product 1||product 2||product 3||product 4|
Now suppose that this table relates to one sales region and that there are three such regions altogether. The following statement will create a three-dimensional array which represents this situation:
+SALES ← 3 6 4⍴72?100
On your screen are (or should be) three blocks of numbers, each of six rows and four columns. These are the three planes, so to speak, of
SALES. To create
SALES you specified three dimensions as the left-hand argument of
⍴ (see above). To select a particular element from
SALES, you also have to give three numbers:
You specified that from
SALES you wanted plane 2, row 5, column 4. In other words you wanted to know the quantity of product 4 sold by salesman 5 in area 2. You've now seen what is meant by three-dimensional data, and are aware that APL treats data as having dimensions. But the key to understanding the next function is to remember that a single number or single character has no dimensions.
As you've seen, the
⍴ function used with two arguments puts specified data into a specified number of rows and columns. The same function used with one argument allows you to enquire about the size (or 'shape') of existing tables and other variables.
To remind yourself of the size of
SALES (the three-dimensional data structure you recently created), type:
⍴SALES 3 6 4
As you see, you've been given the size of each dimension of
SALES. Now create a two-dimensional table and ask the size of that:
TABLE ← 5 3 ⍴ 15 ? 20 ⍴TABLE 5 3
You've been given the size of each of the table's two dimensions. The height of the table is five rows, the length is three columns.
Next create a variable containing a list of numbers and ask its size:
LIST ← 1 2 3 4 5 6 ⍴LIST 6
The list is six numbers long.
Finally put a single number into a variable and ask its size:
NUM ← 234 ⍴NUM
NUM has neither length, height nor any other dimension. It is, as we've already said, the equivalent of a point. APL therefore gives an empty response. By the way, the item enquired about doesn't have to be in a variable. Here we enquire about the size of a directly quoted numeric value:
⍴12 61 502 1 26 0 11 7
And here we ask for the size of a string of characters:
Before you read on, use the one-argument form of the
⍴ function to enquire about the size of some variables in your workspace. Remember that you're really asking about the size of each variable's dimensions.
Characters can be arranged in rows and columns too:
ALF ← 3 5 ⍴ 'ABCDE' ALF ABCDE ABCDE ABCDE
But compare the effect of this next statement with the effect of the last:
NUM ← 3 5 ⍴ 12345 NUM 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 12345
The fact is that
12345 is one number, while
'ABCDE' is five characters. So each single character in the first table is equivalent to each occurrence of
12345 in the second table. Despite their different appearances, both tables contain 15 elements. Notice, though, that while APL has no scruples about putting spaces between the occurrences of
12345 in the numeric table, it doesn't insert spaces in the alphabetic data. Since space is itself a character, it expects you to put in the spaces you require.
Here are a few examples to give you some experience of the way alphabetic data behaves:
MYNAME ← 'GORSUCH' ⍴MYNAME 7 3 7 ⍴ MYNAME GORSUCH GORSUCH GORSUCH
In the last example the seven characters in
'GORSUCH' were arranged as three rows each of seven columns.
In this example the same characters are arranged in three rows of 14 columns. Since
MYNAME contains seven characters, this fits quite neatly, though a column of spaces between the present columns seven and eight would be an improvement.
3 14 ⍴ MYNAME GORSUCHGORSUCH GORSUCHGORSUCH GORSUCHGORSUCH
In the next example, the characters fill a three-row by eighteen-column table. This is not such a neat fit:
3 18 ⍴ MYNAME GORSUCHGORSUCHGORS UCHGORSUCHGORSUCHG ORSUCHGORSUCHGORSU
We'll try again. First we'll put a space at the end of the original character string, making it up to eight characters. Then we'll define a table with sufficient columns for the eight characters to be printed in their entirety five times on each of three rows.
MYNAME ← 'GORSUCH ' ⍴MYNAME 8 3 40⍴ MYNAME GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH GORSUCH
In this final example, this is the result we want to achieve:
ADAMS CHATER PRENDERGAST LEE
See if you can define a table which achieves that result before you look at the solution below.
You want a table of four rows. The difficulty is working out the columns. The columns must accommodate the longest name, which is
PRENDERGAST with 11 characters. However, merely to put the names into four rows of 11 columns won't achieve the desired result:
4 11 ⍴ 'ADAMS CHATER PRENDERGAST LEE' ADAMS CHATE R PRENDERGA ST LEEADAMS CHATER PRE
The other names must he padded out with spaces so that each name plus following spaces exactly fills 11 columns. (For clarity, each space is represented here by a dot.)
4 11 ⍴ 'ADAMS......CHATER.....PRENDERGASTLEE........' ADAMS...... CHATER..... PRENDERGAST LEE........
There's some good news for you if you found that a tedious exercise. APLX has a special facility called
⎕BOX which arranges data into rows and columns for you without any of that bother. (It's a system function and you can read about it in the APLX Language Manual). Doing the counting yourself on this occasion has, however, given you a chance to see how character data behaves.
You might remember that, in the last chapter, we made up lists which contained both characters and numbers. The examples that we have used so far in this chapter have been either characters or numbers. We can make up mixed tables in exactly the same way that we made up other tables. Here's one:
MIXTURE ← 3 3⍴'A' 1 'B' 'C' 2 'D' 'E' 3 'F' MIXTURE A 1 B C 2 D E 3 F
You can't, of course, carry out arithmetical operations on mixed tables, but you can reshape them with
⍴ and select elements just as you did with unmixed tables. Try making up some mixed tables yourself. APLX will try to display the contents of these tables in as neat a fashion as it can - no easy matter when you have mixtures of characters and fractional numbers in the same columns. If you want to investigate these rules, have a look in the APLX Language Manual.
Just to complete the picture, we can make up tables that contain other tables or lists. Again we follow the rules we discussed earlier when making up nested lists. We will use parentheses and quote marks as we did with lists. Here's an example:
NEST ← 2 3⍴(2 2⍴⍳4) (⍳5) 'A NAME' (2 4⍴⍳8) 23 (3 4⍴ 'NAME') NEST 1 2 1 2 3 4 5 A NAME 3 4 1 2 3 4 23 NAME 5 6 7 8 NAME NAME
NEST made up of? It's two rows deep and three columns wide. The first entry in the first row is a 2 row 2 column table made up of numbers, then we have a list of 5 numbers and a list of 6 characters. The second row starts with a numeric table of 2 rows 4 columns, then has a single number and ends with a 3 row 4 column table of characters. Just to check, let's see what the shape of
⍴NEST 2 3
In order to cope with the added complication of nested data, either tables or lists, we have to bring in a new function
≡, called depth.
Depth gives an idea of the degree of nesting that can be found in a variable. This becomes important when you bear in mind that we could make up another variable where some of the elements are themselves nested variables and so on.
A single number or character has depth 0
and a list has depth 1
≡1 2 3 1
So does a table:
≡2 2⍴3 4 5 6 1
Lists and tables which are made up entirely of single numbers or characters will all have depth 1. When at least one element of a list or table already has a depth of 1 (when it is itself a list or a table), then the overall depth of the variable of 2. So our sample variable has a depth of 2:
This idea extends when we make more complicated examples. If one element is of depth 2, then the overall depth of the object is 3. The depth of a variable is always set by the deepest amount of nesting found within it.
BIG_NEST ← NEST NEST ⍴BIG_NEST 2 ≡BIG_NEST 3
BIG_NEST is made up of variables that already have a depth of 2, so it has depth 3. In fact, it's made up of the two objects
NEST forming a two element vector.
The functions introduced in this session were
⍴. (See APLX Language Manual for definitions.)
Some points worth remembering are:
1. Tables are specified and filled in row order.
2. Tables involved in an arithmetic operation must have the same number of rows and columns.
3. Catenate (
,) joins tables with equal numbers of rows.
4. Data has dimensions:
- a single number or character has no dimensions
- a list has one dimension, length
- a table has two dimensions, height and length
- data in APLX can have up to sixty-three dimensions.
5. The result returned by the one-argument form of
⍴ is the size of each dimension of the data you enquired about (e.g. how long it is, or how deep and high).
6. In character tables, every character, including space, is one column.
7. Tables can be made up of a mixture of numbers and characters.
8. Tables can be made up of lists and other tables.
9. Nested tables have depth.
The strength of APL is that almost any logical combination of functions is possible. This means (for example) that the result of an enquiry about a variable's size can be passed along the line to form the argument to the next function:
(⍴'ABC','DEF') + ⍴'GHI' 9
Or to take another example, if you've defined a table like this:
TABLE ← 10 10 ⍴100 ? 100
and you now want to select the first nine numbers in row 1, there is an alternative to typing laboriously:
TABLE[1;1 2 3 4 5 6 7 8 9]
You can instead let the
⍳ function generate the index for you:
These examples are not particularly significant in themselves. They merely indicate the variety of possibilities that exists if you care to experiment. When you've finished your experimentation, try the problems provided.
Q1. Set up a four-row one-column table called
300 42 25 140
And a similarly shaped table called
27.5 15 27.5 27.5
MILES, then multiply the result by 0.01 to produce a table called
Q2. Change the number in column 1 row 3 of
MILES from 25 to 250. Again, multiply
MILES and the result by 0.01 to give
EXPENSES, then reformat
EXPENSES to produce a one-row four-column table.
X as a three-row ten-column table containing random numbers, and
Y as a three-row four-column table also containing random numbers. Add
Y, first taking whatever steps you think necessary to enable the operation to take place.
Q4. Using table
X created in problem 4, add the first and second rows and replace the third row with the result of the addition.
Q5. Create a table which will look like this when displayed:
M I C R O A P L
Q6. What will be the result of each of these
⍴ statements? Predict each result before you press ENTER.
⍴ 'ABC DEF'
⍴ 480 0 1.2
TABLE ← 10 l0 ⍴ 100 ⍴ 1000
⍴ '480 0 1.2
TABLE ← 2 10 3 ⍴ 100 ⍴ l00
MILES ← 4 1 ⍴ 300 42 25 140 RATES ← 4 1 ⍴ 27.5 15 27.5 27.5 +EXPENSES ← 0.01×RATES×MILES 82.5 6.3 6.875 38.5
MILES[3;1] ← 250 +EXPENSES ← 1 4 ⍴ EXPENSES ← 0.01×RATES×MILES 82.5 6.3 68.75 38.5
X ← 3 10 ⍴ 30 ? 100 Y ← 3 4 ⍴ 12 ? 100 X+( 3 6 ⍴ 0) ,Y
Since the problem didn't say which columns of
X Y were to be added to, you may have put the zeroes on the other side:
X+Y,3 6 ⍴ 0
X[3;] ← X[1;]+X[2;]
8 1 ⍴ 'MICROAPL'
Q6. You saw the answers to this problem when you entered the statements.
|<< Previous||Contents||Next >>|
|Home APLX Overview Buy APLX|
Copyright © 1996-2008 MicroAPL Ltd