§21.11. Variations: arrays, logs, queues, stacks, sets, sieves and rings

Lists are highly adaptable, and many other collection-like constructions can be made using them. This section introduces no new material, but simply suggests some of the variations which are possible.

1. The traditional computing term array means a list of values accessed by their entry numbers, often used in mathematical computations. The difference between an array and a list is mostly one of attitude, but usually arrays are fixed in length whereas lists can expand or contract.

2. A log is a list which records the most recently arrived values, but does not allow itself to grow indefinitely. In the following, which remembers the seven most recently taken items, new values arrive at the end while old ones eventually disappear from the front:

The most-recently-taken list is a list of objects that varies.
Carry out taking something (called the item):
    truncate the most-recently-taken list to the last 6 entries;
    add the item to the most-recently-taken list.
After taking:
    say "Taken. (So, your recent acquisitions: [most-recently-taken list].)"

Note that the most-recently-taken list begins play as the empty list, grows as the first few items are taken, but then stabilises at length 7 thereafter. If we need to remember recent history, but only recent history, then a log is better than a list which can grow indefinitely, because there is no risk of speed reduction or memory exhaustion in a very long game.

3. A queue is a list of values which are waiting for attention. New values join at the back, while those being dealt with are removed from the front (whereupon the whole queue moves up one). An empty queue means that nobody is waiting for attention: but there is, in principle, no upper limit to the size of a queue, as anyone who has tried to make a couchette reservation at Roma Termini will know.

Queues typically form when two independent processes are at work, but going at different or variable speeds. An empty queue looks just like any other list:

The queue is a list of objects that varies.

(Invariably people, in what follows, but we'll make it a "list of objects" to allow for other possibilities too.) Once we identify a "new customer", we can join him to the queue thus:

add the new customer to the queue;

The process of serving the customers needs to make sure there is actually somebody waiting in the queue before it does anything:

Every turn when the number of entries in the queue is not 0:
    let the next customer be entry 1 of the queue;
    say "[The next customer] is served and leaves.";
    remove entry 1 from the queue.

Of course queues can also be constructed which empty from other positions, rather than the front: or we could make what computer scientists sometimes call a deque, a "double-ended queue" where new values arrive at both ends.

4. A stack is like a queue except that values arrive at, and are removed from, the same end. Stacks are slightly faster if the active end is the back rather than the front, though this will only be noticeable if they grow quite large.

To put a value V onto a stack S (which is known as "pushing") is simple:

add V to S;

And to remove a value from the top of the stack (which is known as "pulling"):

let N be the number of entries in S;
let V be entry N of S;
remove entry N from S;

Note that the middle line, accessing entry N, will fail if N = 0, that is, if the stack is empty: Inform's list routines will produce a run-time problem message.

Stacks are useful if some long-term process is constantly being interrupted by newer and more urgent demands, but they can also be used in planning. If a character has a long-term goal, which needs various short-term goals to be achieved along the way, then a stack can represent the goals currently being pursued. The top of the stack represents what the character is trying to achieve now. If the character realises that it needs to achieve something else first, we put that new goal onto the top of the stack, and it becomes the new current goal. When the character completes a task, it can be removed, and we can go back to trying to finish whatever is now on top. When the stack is empty, the character has achieved the original goal.

5. Notoriously, set has 464 distinct meanings in the Oxford English Dictionary, making it the single most ambiguous word in the language. Here we mean not the home of a badger or the Egyptian god of the desert, but the mathematical sense: a collection of values (sometimes called "elements") without duplicates, and which is normally written in brace notation and in some natural order for the reader's convenience.

The trick here is to maintain the principle that, at all times, our list is sorted in order and contains no duplicates. To provide an example, we start with two sets of numbers:

let S be {2, 4, 8, 16, 32, 64};
let T be {2, 4, 6, 10};

Here we add an element to T:

add 8 to T, if absent; sort T;

The "if absent" clause ensures that no duplicate can occur, and by sorting T afterwards, we maintain the principle that a set must remain in order - so T is now {2, 4, 6, 8, 10}, not {2, 4, 6, 10, 8}. (Inform's sorting algorithm is fast on nearly-sorted lists, so frequent sorting is not as inefficient as it might look.)

We next take the union of T and S, that is, the set containing everything which is in either or both:

let U be S; add T to U, if absent; sort U;

This makes U = {2, 4, 6, 8, 10, 16, 32, 64}, and once again no duplicates occur and we preserve the sorting. The intersection of T and S, the set of elements in both of them, is a little trickier:

let I be T;
repeat with the element running through T:
    if the element is not listed in S, remove the element from I.

(Faster methods could be devised which exploit the sortedness of T and S, but are not worth it for shortish lists.) This produces I = {2, 4, 8}. Lastly, we can form the set difference, consisting of those elements which are in S but not in T:

let D be S; remove T from D, if present;

Here, as with intersection, since all we do is to strike out unwanted elements, the surviving ones remain in order and there is no need to sort when we are finished. This produces D = {16, 32, 64}.

6. A sieve is used to make a complicated choice where there are many constraints, by ruling out impossible cases to see what is left. The term derives from the kitchen utensil (for sieving fine grains of flour), but via the name of the "sieve of Eratosthenes", an ancient Greek method for determining the prime numbers.

Using a sieve is much like using a set, and the difference is mainly one of outlook - we are interested in what does not belong, rather than what does.

7. A ring is not so much a row of values, more a circle, with the last and first entries thought of as adjacent. One position is usually thought of as special, and is the place where new items are added: this may as well be entry 1. For instance, to add "new item" to the ring:

add the item at entry 1 in the ring;

To set "item" to the frontmost value and extract it from the ring:

let the item be entry 1 of the ring;
remove entry 1 from the ring;

And we can rotate the ring in either direction, making a different entry the new entry 1 and therefore the new frontmost value:

rotate the ring;
rotate the ring backwards;


arrow-up.pngStart of Chapter 21: Lists
arrow-left.pngBack to §21.10. Lengthening or shortening a list
arrow-right.pngOnward to Chapter 22: Advanced Phrases: §22.1. A review of kinds

*ExampleYour Mother Doesn't Work Here
Your hard-working mother uses a list as a stack: urgent tasks are added to the end of the list, interrupting longer-term plans.

*ExampleI Didn't Come All The Way From Great Portland Street
In this fiendishly difficult puzzle, which may perhaps owe some inspiration to a certain BBC Radio panel game (1967-), a list is used as a set of actions to help enforce the rule that the player must keep going for ten turns without hesitation, repetition, or deviating from the subject on the card.

*ExampleCircle of Misery
Retrieving items from an airport luggage carousel is such fun, how can we resist simulating it, using a list as a ring buffer?

*ExampleSieve of Eratosthenes
The haughty Eratosthenes of Cyrene will nevertheless consent to sieve prime numbers on request.

Fibonacci (a posthumous nickname) spread Arabic mathematical learning across Europe in the 13th century, and it's curious that his name lives on only for a single sequence.

paste.png "The Fibonacci Sequence"

Pisa is a room. Leonardo Fibonacci is a man in Pisa. "The modest Italian mathematician, Leonardo Fibonacci (1170-1250), beams at you."

Sequencing is an action applying to one number. Understand "sequence [number]" as sequencing.

Instead of sequencing, say "You make a feeble attempt, sketching in the sand, but it goes nowhere. Leonardo is sympathetic. 'Often goes wrong for me, too, actually. I didn't even invent the thing - the ancient Indians knew about it first.'"

Persuasion rule for asking Leonardo to try sequencing: persuasion succeeds.

Report Leonardo sequencing:
    let N be the number understood;
    say "Leonardo scratches his head and makes self-deprecating remarks, before coming up with [the first N terms of the Fibonacci sequence]."

An array need not be fixed in length, as the following example shows:

To decide what list of numbers is the first (F - a number) terms of the Fibonacci sequence:
    let the Fibonacci sequence be {1, 1};
    let N be 3;
    while N < F:
        let the last term be entry (N - 1) of the Fibonacci sequence;
        let the penultimate term be entry (N - 2) of the Fibonacci sequence;
        let the next term be the last term plus the penultimate term;
        add the next term to the Fibonacci sequence;
        increment N;
    decide on the Fibonacci sequence.

Test me with "sequence 20 / leonardo, sequence 20".

The result of "the first 20 terms of the Fibonacci sequence" is "1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584 and 4181". This is a sequence which has a knack of turning up in odd places - it was found in the 1970s to be related to the rings of florets in a sunflower, for instance - and here it is in a book about interactive fiction.

*ExampleThe Fibonacci Sequence
The modest Leonardo Fibonacci of Pisa will be only too happy to construct his sequence on request, using an array.

Fibonacci (a posthumous nickname) spread Arabic mathematical learning across Europe in the 13th century, and it's curious that his name lives on only for a single sequence.

paste.png "The Fibonacci Sequence"

Pisa is a room. Leonardo Fibonacci is a man in Pisa. "The modest Italian mathematician, Leonardo Fibonacci (1170-1250), beams at you."

Sequencing is an action applying to one number. Understand "sequence [number]" as sequencing.

Instead of sequencing, say "You make a feeble attempt, sketching in the sand, but it goes nowhere. Leonardo is sympathetic. 'Often goes wrong for me, too, actually. I didn't even invent the thing - the ancient Indians knew about it first.'"

Persuasion rule for asking Leonardo to try sequencing: persuasion succeeds.

Report Leonardo sequencing:
    let N be the number understood;
    say "Leonardo scratches his head and makes self-deprecating remarks, before coming up with [the first N terms of the Fibonacci sequence]."

An array need not be fixed in length, as the following example shows:

To decide what list of numbers is the first (F - a number) terms of the Fibonacci sequence:
    let the Fibonacci sequence be {1, 1};
    let N be 3;
    while N < F:
        let the last term be entry (N - 1) of the Fibonacci sequence;
        let the penultimate term be entry (N - 2) of the Fibonacci sequence;
        let the next term be the last term plus the penultimate term;
        add the next term to the Fibonacci sequence;
        increment N;
    decide on the Fibonacci sequence.

Test me with "sequence 20 / leonardo, sequence 20".

The result of "the first 20 terms of the Fibonacci sequence" is "1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584 and 4181". This is a sequence which has a knack of turning up in odd places - it was found in the 1970s to be related to the rings of florets in a sunflower, for instance - and here it is in a book about interactive fiction.

Fibonacci (a posthumous nickname) spread Arabic mathematical learning across Europe in the 13th century, and it's curious that his name lives on only for a single sequence.

paste.png "The Fibonacci Sequence"

Pisa is a room. Leonardo Fibonacci is a man in Pisa. "The modest Italian mathematician, Leonardo Fibonacci (1170-1250), beams at you."

Sequencing is an action applying to one number. Understand "sequence [number]" as sequencing.

Instead of sequencing, say "You make a feeble attempt, sketching in the sand, but it goes nowhere. Leonardo is sympathetic. 'Often goes wrong for me, too, actually. I didn't even invent the thing - the ancient Indians knew about it first.'"

Persuasion rule for asking Leonardo to try sequencing: persuasion succeeds.

Report Leonardo sequencing:
    let N be the number understood;
    say "Leonardo scratches his head and makes self-deprecating remarks, before coming up with [the first N terms of the Fibonacci sequence]."

An array need not be fixed in length, as the following example shows:

To decide what list of numbers is the first (F - a number) terms of the Fibonacci sequence:
    let the Fibonacci sequence be {1, 1};
    let N be 3;
    while N < F:
        let the last term be entry (N - 1) of the Fibonacci sequence;
        let the penultimate term be entry (N - 2) of the Fibonacci sequence;
        let the next term be the last term plus the penultimate term;
        add the next term to the Fibonacci sequence;
        increment N;
    decide on the Fibonacci sequence.

Test me with "sequence 20 / leonardo, sequence 20".

The result of "the first 20 terms of the Fibonacci sequence" is "1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584 and 4181". This is a sequence which has a knack of turning up in odd places - it was found in the 1970s to be related to the rings of florets in a sunflower, for instance - and here it is in a book about interactive fiction.

*ExampleEyes, Fingers, Toes
A safe with a multi-number combination, meant to be dialed over multiple turns, is implemented using a log of the last three numbers dialed. The log can then be compared to the safe's correct combination.

*ExampleLugubrious Pete's Delicatessen
In this evocation of supermarket deli counter life, a list is used as a queue to keep track of who is waiting to be served.