Popup YouTube Video
Sheerpower Logo

Arrays


Understanding Traditional Arrays

Arrays are fundamental data structures that let you store a list of items in a single variable. Think of them as a set of numbered slots, each holding a value. In Sheerpower, arrays are a simple way to manage lists, but it's also important to know when a more powerful tool, like a Cluster Array, is a better choice.

1. The Simple Case: Fixed-Size Arrays

If you know exactly how many items you need to store, you can create a fixed-size array using the dim statement.

! Create an array with 5 slots for names dim names$(5) ! Assign values to each slot using its index names$(1) = "Alice" names$(2) = "Bob" names$(3) = "Charlie" print "The second name is: "; names$(2)

This creates an array that looks like this:

1
"Alice"
2
"Bob"
3
"Charlie"
4
 
5
 
Note: By default, the lowest index of an array is 1. However, you can specify a different range, such as dim myarray(0 to 5) or even dim myarray(-10 to 30).

2. Needing More Space: Resizing with redim

What if you create an array and later realize you need more slots? You can use the redim statement to expand it. Importantly, redim preserves all the existing data in the array.

So "fixed" is worth defining: an array declared with a size, such as dim names$(5) or dim grid(2, 3), is fixed in its number of dimensions, not in its size. redim names$(200) and redim grid(4, 5) change the bounds; redim grid(6) is a compile error, because that would change how many subscripts the array takes. Only an expandable array (dim x(*)) can change its number of dimensions.

An expandable array (the next section) can go further: redim can give it a different number of dimensions, keeping the data in order. That is covered on the Array Math page. See Array Math Functions, Index Lists & Slices, Solve(), Sort(), and More.

dim names$(5) names$(1) = "Alice" names$(2) = "Bob" names$(3) = "Charlie" ! We have our array of 5 names, with 3 filled redim names$(10) ! Resize the array to have 10 slots ! The original data is still there print "The second name is still: "; names$(2) ! Now we can add a new name in a new slot names$(6) = "Frank" print "The sixth name is: "; names$(6)

Visually, the redim operation does this:

names$(5)
redim names$(10)
names$(10)

3. Growing as You Go: Expandable Arrays

What if you don't know the size at all and want to add items one by one? Declare the array with an open bound, written as an asterisk:

! Create an expandable array for a shopping list dim shopping_list$(*)

To add an item, assign to (*). This appends the item to the end of the array, making it grow automatically. Reading (*) gives you the last element, and size() tells you how many items there are.

print "Building shopping list..." shopping_list$(*) = "Milk" ! Appends "Milk", size is now 1 shopping_list$(*) = "Bread" ! Appends "Bread", size is now 2 shopping_list$(*) = "Cheese" ! Appends "Cheese", size is now 3 print "My list has "; size(shopping_list$); " items." print "The second item is: "; shopping_list$(2) print "The last item is: "; shopping_list$(*)

The first element is number 1, as usual. If you want the numbering to start somewhere else, give the lower bound and leave the upper bound open: dim scores(0 to *) starts at 0, so the first append lands in element 0 and size() still counts the items.

To empty an expandable array and start over, re-declare it the same way: redim shopping_list$(*) (older code: redim shopping_list$(0)).

Walking an array with FOR/NEXT

The most common thing to do with any array is to visit every element, and the for loop from the previous page is built for it. size() supplies the upper bound, so the loop is right however many items the list holds:

dim shopping_list$(*) shopping_list$(*) = "Apples" shopping_list$(*) = "Bread" shopping_list$(*) = "Milk" for i = 1 to size(shopping_list$) print i; ". "; shopping_list$(i) next i
Compatibility note: older programs declare an expandable array as dim list$(0) and append with list$(0) = value. Both still work exactly as before, and list$(*) = value may be used on such an array too. For new code, write dim list$(*) and list$(*) = value — it says what it means.
(*) works on every array. A fixed array such as dim buf(3) or dim grid(2, 3) has an append cursor too: buf(*) = value puts the value in the next unused slot (a 2D array fills row by row, the order print shows) and buf(*) reads the last one appended. The difference is room: a fixed array never grows, so once every slot is used the next append raises SUBOUTBND ("no room to append"). Only dim list$(*) keeps growing. A fill or an assignment to an element moves the cursor past what it wrote, so fill w with 1, 2, 3 followed by w(*) = 4 lands on w(4). The cursor survives a reshape in storage order: redim keeps it when the array grows and caps it when the array shrinks, so four appended items followed by redim x(2, 3) leave the cursor at 4 and the next append fills the fifth slot. A whole-array assignment (x = y * 2) fills every slot, so afterwards the cursor is at the end and an append on a two-dimensional result raises SUBOUTBND until the array is one-dimensional again.

4. Filling an Array in One Statement: fill

You have 100 scores to zero out before a new round, a month of days to number, or a week of names to load. Element by element works, but these most common jobs — give every element a starting value, number the elements, or load a small known list — deserve one line each. The fill statement does exactly that, in three forms.

And fill is not a one-time load — run it as often as you like. A plain fill reloads from the start, fill x(*) adds to the end, and fill x(pos) changes elements in place. So fill is also your append: Sheerpower needs no separate append statement, and the same statement grows an expandable array or edits a fixed one.

Where a fill starts — the one rule behind every form below:
  • fill x with ... starts at element 1 (the array's lower bound).
  • fill x(*) with ... starts at the slot after the last one used — the same slot x(*) = v writes.
  • fill x(expr) with ... starts at element expr (fill grid(r, c) at that cell).
From there the values run on in storage order, whichever form follows with. Only the plain form discards what an expandable array holds; (*) and (expr) always work inside or onto what is there.

Broadcast: everyone gets the same value

dim scores(100) fill scores with 0 ! all 100 elements are now 0 dim status$(50) fill status$ with 'pending' ! every element starts as 'pending' dim nines(*) fill nines with 100 of 9 ! an expandable array: a hundred 9s (see "Many of the same" below) fill nines with 0 ! ...and later, zero everything it currently holds

The value is evaluated for every element — so fill dice with rnd(6) rolls every die, and fill ids$ with _gid$ gives every slot its own id. A literal, a const or a plain variable is simply copied; an expression is computed again for each slot. After any fill, _integer holds how many elements were filled.

On an expandable array a one-value fill covers whatever the array currently holds — fill nines with 0 zeroes all hundred, and nines(*) = 1 still appends a 101st afterwards. To give an expandable array a shape first, use redim: redim grid(2, 3) then fill grid with 0.

A range of values: seq()

dim slot(12) fill slot with seq(1, 12) ! slot(1)=1, slot(2)=2, ... slot(12)=12 dim rate(11) fill rate with seq(0, 1, 0.1) ! 0, .1, .2, ... 1 -- EXACT decimals dim countdown(10) fill countdown with seq(10, 1, -1)

seq(a, b [, step]) builds the numbers from a to b as an array, and fill lays them into yours. The step defaults to 1; a descending range needs a negative step, so without one seq(10, 1) is empty — the same rule as for i = 10 to 1. And it is not only seq(): ANY array expression fills this way — filter(), sort(), arithmetic like src * 2, or another array — its elements become the values. An array is really just a list item that splices in its elements, so you can mix arrays and plain values freely: fill x with seq(1, 5), 99, seq(100, 110).

List: one value per element

dim day_names$(7) fill day_names$ with 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ! On an EXPANDABLE array, a list DEFINES the contents -- the ! array-literal pattern. The array is reset first, then loaded: dim menu$(*) fill menu$ with 'Coffee', 'Tea', 'Juice' print size(menu$) ! 3

Values are full expressions, assigned left to right. Giving more values than the array has elements raises the catchable exception FILLOVER — and for a value list the check happens before anything is written, so a caught overflow leaves the array untouched. Giving fewer fills just those elements and leaves the rest alone.

Adding to the end: fill x(*)

A plain fill writes from element 1 — which is why a second fill menu$ with ... replaces the menu rather than lengthening it. To add values after what is already there, put the append cursor in the parentheses: fill x(*) with ... writes from the slot after the last used one, the same place x(*) = v appends a single value. All three forms work:

dim menu$(*) fill menu$ with 'Coffee', 'Tea', 'Juice' fill menu$ with 'Coffee', 'Tea', 'Juice' ! replaces: size is still 3 fill menu$(*) with 'Water', 'Milk' ! adds: size is now 5 dim slot(*) fill slot with seq(1, 12) fill slot(*) with seq(13, 24) ! an array appends too: size 24 fill slot(*) with 99 ! one value: the same as slot(*) = 99 dim ten(10) fill ten with 1, 2, 3 ! elements 1..3 fill ten(*) with 4, 5 ! continues at 4 and 5

On a fixed array fill x(*) continues from the cursor and raises FILLOVER when there is no room; on an expandable one it grows. The cursor is moved by every write — a fill, an assignment, or an indexed write — so q(2) = 5 followed by fill q(*) with 7, 8 writes q(3) and q(4). On a fresh array the cursor is at the start, so fill x(*) with 1, 2, 3 and fill x with 1, 2, 3 give the same result; the difference shows only once the array holds something.

Starting at a position: fill x(20)

The third place a fill can start is any element you name. The rule has one shape: fill x starts at element 1, fill x(*) at the append cursor, and fill x(20) at element 20. From there the values run on in storage order, so on a two-dimensional array fill grid(2, 1) with 1, 2, 3 fills row 2.

dim buf(30) fill buf with seq(1, 30) fill buf(20) with 1, 2, 3, 4 ! elements 20..23; 19 and 24 untouched fill buf(28) with 3 of 0 ! 28..30 dim x(*) fill x with 10, 20, 30, 40, 50 fill x(3) with 9 ! the same as x(3) = 9: size stays 5 fill x(9) with 8 ! past the end: 6..8 become 0, size 9

The start must be an element of a fixed array — naming one past the end raises SUBOUTBND, the same as x(11) = 1 would — and a run that would pass the end raises FILLOVER before anything is written. On an expandable array the start may lie past the end, and the gap is filled with zeros, exactly as x(9) = 8 does. A positioned fill never discards what the array holds; only a plain fill x with ... does that.

Many of the same: n of value

Fifty 9s on the end of an array is not a range and not a list you want to type. Say how many: a list item may be n of value, and it mixes with ordinary items. To repeat a whole group, put the group in parentheses.

fill x(*) with 50 of 9 ! fifty 9s on the end fill x with 50 of 9 ! the array IS fifty 9s fill row with 3 of 0, 1, 2 of 5 ! 0, 0, 0, 1, 5, 5 fill x with 3 of (1, 2, 3) ! 1, 2, 3, 1, 2, 3, 1, 2, 3 fill x with 2 of (3 of 0, 1) ! groups nest: 0, 0, 0, 1, 0, 0, 0, 1 fill status$ with 3 of 'pending', 'done' ! pending, pending, pending, done fill x(*) with size(y) of 0 ! the count is any expression

of binds to the one value beside it — 3 of 1, 2, 3 is 1, 1, 1, 2, 3 — so parentheses are what make a group. A count of 0 contributes nothing. Every value inside an n of is evaluated for each element it fills: 50 of rnd(6) is fifty rolls, 5 of _gid$ five different ids. A plain list item is evaluated once, before anything is written, so fill x with x(2), x(1) swaps. Too many values for a fixed array is still FILLOVER, decided before anything is written, and _integer is the total number written.

Good to know:
  • fill checks sizes at runtime against the array's current extent, so it plays correctly with redim.
  • A partial fill leaves the tail untouched — fill writes exactly what you gave it.
  • On an expandable array, a plain fill means "the array now IS this list" — existing contents are discarded first. fill x(*) with ... is the form that adds to the end. A one-value fill on an expandable array covers whatever it currently holds.
  • All three forms work on any array, including two-dimensional ones: a range or list flows through the whole array in storage order (row by row), whatever its shape — fill grid with 1, 2, 3, 4, 5, 6 on dim grid(2, 3) fills row 1 with 1, 2, 3 and row 2 with 4, 5, 6.
One statement, not six. Notice how much fill is: three places to start (x / x(*) / x(pos)) times a value that can be a broadcast, a seq(), a list, a spliced array, or n of repeats, over a fixed or an expandable array. That one primitive does the work most languages split across fill, append, extend, insert, range, and a repeat operator — and because the value is evaluated per element, it also generates (fill dice with rnd(6)). Learn the three start points and the value forms once, and you have covered nearly all of array mutation.

5. Seeing an Array: print and print array

Once an array is loaded you want to see it, and writing a loop just to look is tedious. You can hand a whole array straight to print. The elements come out lined up in columns, sized to the widest one; a two-dimensional array prints one row per line, like a table:

dim scores(4) fill scores with 90, 85, 77, 92 print scores ! 90 85 77 92 print 'scores: '; scores ! scores: 90 85 77 92 dim grid(2, 2) fill grid with 5 print grid ! 5 5 (then on the next line) 5 5

When you want control over the layout, use the print array statement — the same shape as print cluster, with a colon and a comma-separated option list:

print array scores: list ! one element per line print array scores: list, index ! 1: 90 / 2: 85 / 3: 77 / 4: 92 dim day_names$(3) fill day_names$ with 'Mon', 'Tue', 'Wed' print array day_names$: csv ! "Mon","Tue","Wed" print array day_names$: quoted ! "Mon" "Tue" "Wed" print array scores #ch: list ! to an open file channel

The options are list (one element per line), index (show each element's subscript — a 2D array shows (row,col)), csv (strings quoted, commas with no spaces), and quoted (the aligned display, but each string element wrapped in quotes). Expandable arrays print what has been appended so far; an empty one prints an empty line.

quoted earns its place when a string might be empty or carry stray spaces — the plain display cannot show either, but quotes make both plain. An empty element appears as "", a trailing space sits inside the quotes, and an embedded quote is doubled (as in csv). Numbers are never quoted, so quoted changes nothing for a numeric array. It combines with the others: : list, quoted quotes one element per line, : index, quoted labels and quotes each.

dim raw$(4) raw$(1) = "apple " ! a trailing space raw$(2) = "" ! empty raw$(3) = " pear" ! a leading space raw$(4) = "ok" print raw$ ! apple pear ok -- boundaries invisible print array raw$: quoted ! "apple " "" " pear" "ok"

6. Always in Order: sorted

A leaderboard, a list of names for a menu, the readings from a sensor that you want to scan from lowest to highest — some arrays are only ever wanted in order, and sorting them yourself after every change is a chore that is easy to forget. Say so once, on the dim, and the array keeps itself in order:

dim scores(*) sorted scores(*) = 72 scores(*) = 95 scores(*) = 61 scores(*) = 88 print scores ! 61 72 88 95 -- no sort statement anywhere print "lowest: "; scores(1); " highest: "; scores(*) dim names$(*) sorted fill names$ with 'Pat', 'alice', 'Bob' print names$ ! alice Bob Pat -- case does not matter to the order

Every write keeps the order: an append with (*) lands at its place, an element write moves the new value to its place, and a fill sorts once. Numbers order numerically; strings order case-blind. Because the array is always in order, a position is a rank: scores(1) is the lowest score and scores(*) the highest, and scores(1) = 99 replaces the lowest score with 99, which then takes its own rank. Everything you have read on this page — print, size(), the statistics functions, filter() — sees the sorted order.


Note: sorted arrays are best for simple tasks. Because the elements are kept in sorted order, only two positions have a guaranteed meaning: arrayname[1] always holds the lowest value, and arrayname[size(arrayname)] always holds the highest. Any other position may hold a different element after new data is added, so never save an index and expect it to refer to the same value later.

7. Beyond Lists: Array Math and Statistics

Arrays can also be computed with as a whole — z = x * 100 scales every element at once, matmul(a, b) multiplies matrices, and solve(a, b) finds the unknowns behind known totals. String arrays take part: every string function maps over one (ucase$(names$)), + joins element by element, a comparison such as names$ = "bob" is a mask, and sort(), unique() and isin() work on strings as on numbers. That is a different level of work from this page; when you need it, it has a discussion of its own: Array Math Functions, Index Lists & Slices, Solve(), Sort(), and More. Extensive statistics are also available. See Cluster and Traditional Array Statistics.

8. The Next Step: When to Use Cluster Arrays Instead

Traditional arrays are great for simple lists of single values. However, most business data is structured. For example, instead of just a list of product names, you usually need to store the product's name, its price, and its quantity together.

For this kind of structured data, the Cluster Array is the preferred and more powerful tool in Sheerpower. Think of it as a spreadsheet in memory, where each row is a complete record.

Recommendation: While it's important to understand traditional arrays, for most modern data handling tasks in Sheerpower, you should use this: Cluster Arrays.
Summary: You've learned the ways to work with traditional arrays:
  1. Fixed-Size: dim array(10)
    When you know the exact size upfront.
  2. Resizable: redim array(20)
    When you need to expand an array later while keeping its data.
  3. Expandable: dim array(*)
    When you need to add items one by one with array(*) = value (dim array(0) / array(0) = value is the older spelling, still supported).
  4. Filling: fill array with ...
    One statement to load an array — a broadcast value, a numeric range with an optional step, or a comma-separated list of values.
  5. Printing: print array / print array x: list, index, csv, quoted
    Hand the whole array to print for a one-line view, or use print array for a layout.
  6. Array math: z = x * 100, matmul(a, b), solve()
    Whole-array computation, on its own page: Array Math Functions, Index Lists & Slices, Solve(), Sort(), and More.
For anything more complex than a simple list, explore Cluster Arrays next!

All told, Sheerpower gives you 17 core array operations, made open-ended by array-mapping over the whole function library (built-in and user-defined), with slicing/indexing and the fill/print/structure machinery around them. The list below shows every one, all in one place.

(Show/Hide the Full List of Array Features)
(Show/Hide Sheerpower Arrays Takeaways)
Hide Description

    

       


      

Enter or modify the code below, and then click on RUN

Looking for the full power of Sheerpower?
Check out the Sheerpower website. Free to download. Free to use.