Arrays

From FizzFuzz

(Redirected from Array)
Jump to: navigation, search

Arrays are a special type of variable that can store multiple values of the same data type. In FizzFuzz, Arrays are very similar to C and C++-style arrays in definition. One of the most notable exceptions to this is that arrays begin indexing at 1, meaning the first element in an array is accessed at the first index as opposed to the zeroth index. As with C/C++ arrays, FizzFuzz arrays are a collection of values of a single data type or class. Unlike C and C++-style arrays, FizzFuzz arrays are dynamic-length and can easily have their size changed and their elements altered.

Contents

Defining An Array

Arrays are defined using the syntax,

[access] [modifier] datatype identifier[[size]] [= {[elem1 [, elem2 [, ... [ elemn ]]]]}];

where:

  • access is an optional modifier indicating the access level of the variable. If not provided, this defaults to public.
  • modifier is any modifier to the data type of the array.
  • datatype is the data type of the array.
  • identifier is the identifier, or name, of the array. The constraints are the same as they are for a variable.
  • size is the number of elements the array can store. If this value is not provided, one of two things can occur:
    1. If the array is immediately assigned a value, nothing will happen and the code will continue as normal.
    2. If the array is simply declared without a size, and not assigned an array or value right away, then the compiler will output an error.
  • {elem1, elem2, ..., elemn} are the values of the array. If the array is not assigned any values, then the values are null.

Zero-Length Arrays

A zero-length array is an array initialized with a size of zero. They can otherwise be treated like any other array, with the caveat that any look-up operation on the array fails (due to array[0] being undefined.) The primary purpose they serve is that they can exist before being instantiated, so that they can have a value assigned to them. This is useful if, for example, the programmer knows a value will be assigned to that array but doesn't know what the length of this array will be. Attempting to assign values to a zero-length array will cause compiler errors, so the final syntax is,

[access] [modifier] datatype identifier[0];

where access, modifier, datatype, and identifier are all the same as the they are for a normal array declaration.

Below is an example of this in use.

int [] GenerateRandomArray(int array_lower, int array_upper, int random_lower, int random_upper)
// This returns an array of a random size, with a random set of values.
{
    mersenne_twister mersenne = new;
    int array[mersenne.Generate(array_lower, array_upper)];
 
    for(int i = 1; i <= array[]; i ++)
        array[i] = mersenne.Generate(random_lower, random_upper);
 
    return array;
}
 
void main()
{
    int array[0];
    output << array[]; // This outputs 0.
 
    array = GenerateRandomArray(5, 10, 1, 100);
    output << array[]; // This outputs a value between 5 and 10,
                       // inclusive.
}

Array Initialization

Arrays can be initialized a number of different ways. The most simple way is to assign a basic array upon declaration. This uses the syntax specified above:

[....] identifier[[size]] = {[elem1 [, elem2 [, ...[, elemn]]]]};

Where elem1, elem2, ..., elemn are elements that fit the constraint of the data type. If size is defined and size > 0, then nsize. Below are two examples of initializing an array.

// Initializes an integer array with ten integers.
int ints[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
 
// Initializes a character array of size 10 with three characters. The
// other seven values of the array will be set equal to null.
char chars[10] = {'a', 'b', 'c'};

Repetitious Initialization

Another way to initialize an array is to use the ... operator. This can be used to indicate to the compiler that a sequence indicating by indicating the sequence to the compiler, and then following it with the ... operator.

[....] identifier[[size]] = {elem1 [, elem2[, ...[ elemn]]] ... [cutoff]};

In repetitious notation, size must only be defined if cutoff is not. cutoff is the number of elements the provided pattern will repeat to. If both size and cutoff are defined, then sizecutoff. If size < cutoff, then when the patterned array is assigned, anything past the sizeth element is ignored.

Using this notation, at least elem1 must be defined. If not, the compiler will produce an error. If up to elemsize is defined, assuming size is defined, then the use of repetitious array is effectively equivalent to simple array initialization, shown above.

A demonstration of this syntax is below.

int array[10] = {0 ...}; // Defines an integer array of size ten, and
                         // population it with the value 0.
array = {1, 2 ...}; // Redefines it, so that the contents will be
                    // {1, 2, 1, 2, 1, 2, 1, 2, 1, 2}.
array = {1 ... 20}; // And defines it again, with a new size. This time,
                    // it will have twenty values, equal to 1.

Sequence Initialization

Full Article: Sequences

Sequence initialization uses a function as a sequence to generate the values in the array.

[....] identifier[[size]] = {f1(x1) : int x1 = a1..b1 [, f2(x2) : int x2 = a2..b2 [, ... [,  fn(xn) : int xn = an..bn ]]]};

In sequence initialization notation, the size is optional. If the total number of elements exceeds size, then the sizeth element will be the cut-off, and others will be ignored.

f1, f2, ..., fn are functions that will be used to populate the array. x1, x2, ..., xn are the arguments for their corresponding functions, and they act over a set of integers from an to bn, as specified by the programmer. These functions do not have to be a call to an external function, but can also simply be an expression acting on xn.

In the case of the function f1(x1) acts over 1 to size, then if a = size...

[....] array[size] = {f(x) : int x = 1..a};

... is equivalent to...

[....] array[size] = {f(x) : int x = 1..array[]);

... which is equivalent to...

[....] array[size] = {f(x) : int x};

A few examples of sequence initialization are provided below.

// Define two functions to use.
long float Square(long float x)
{
    return x ** 2;
}
 
long float SquareRoot(long float x)
{
    return x ** (1/2);
}
 
// Populates the array with a parabola from -10 to 10.
long float alpha[] = {Square(x) : int x = -10..10};
 
// Populates the array with the values of the sqrt from 0 to 10.
long float beta[] = {SquareRoot(x) : int x = 0..10};
 
// Uses the Square() function from -10 to 0, and then the SquareRoot()
// function from 1 to 10.
long float gamma[] = {Square(x) : int x = -10..0, SquareRoot(x) : int x = 1..10}; 
 
// Uses an expression and calculates the value of that expression from
// 1 to 10.
long float delta[10] = {x/(x + (x ** (1/2))) : int x};

Accessing Elements

As in C/C++, elements of an index are accessed by placing the index in brackets, following the identifier of the array. As arrays begin indexing at 1, not 0, the value of 0 is undefined in the context of an array except for zero-length arrays. The index can also be negative, between -1 and -arraysize, where arraysize is the size of the array. A negative index is equal to arraysize - |n| + 1. Hence, an index of -1 is equal to arraysize, or the last index of the array. Therefore, the syntax for accessing a single element is...

array[n];

... where n is an integer in [-arraysize, -1]∪[1,arraysize]. Below is an example of accessing, modifying, and outputting single values of an array.

int array[] = {1, 2, 3, 4, 5};
 
array[1] = 5; // The first element in the array is changed to five.
array[-1] = 1; // The last element in the array is changed to one.
 
output << array[-5]; // This outputs the first element in the array, "5".
output << array[5]; // This outputs the last element in the array, "1".
 
output << array[0]; // As the zeroth index is undefined, this will
                    // result in an error.

Accessing Multiple Elements

FizzFuzz arrays can have more than a single element selected and modified at once. This is done by using the .. and , operators. These allow the programmer to indicate multiple selections from the array. The .. operator allows the programmer to specify a range of values, while the , operator allows the program to specify multiple values. These can be used in conjunction, to specify multiple ranges of values.

// The base array we'll use.
int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
 
// This creates an array foo that uses the 3rd through 8th elements of
// the array array to populate it.
int foo = array[3..8];
foo = array[3, -3]; // This creates the same array as above.
 
// This creates an array using the 1st, 3rd, 5th, 7th, and 9th elements
// of array.
int bar = array[1, 3, 5, 7, 9];
bar = array[-10, -8, -6, -4, -2]; // The same array as above.
 
// Creates an array that uses the 1st through 4th and 7th through 10th
// elements to generate the array.
int foobar = array[1..4, 7..10];
foobar = array[1..4, -4..1]; // The same array as above.

Selecting multiple elements from an array itself produces an array, as implied by the above example.

Using An Array

In addition to the above syntax, providing an integer array as the index to an array produces the same result, and with the same caveats as for a normal index: The value must be an integer, can not be 0, and must be between ±1 and ±size. Technically, the above method utilizing the .. and , operators as, in this context, it generates an array of integers. This is not an explicit use of arrays, but an implicit use of one. Below is an example of using an array:

int [] GetEvenIndices(int array[])
{
    int indices[array[]]; // The max number of elements in the return array
                          // are equal to the size of the array.
    int index = 1;
    for(int i = 1; i <= array[]; i ++)
    {
        if((array[i] % 2) == 0)
            indices[index ++] = i;
    }
 
    while(array[-1] == null)
    // While there are null elements at the end of the array, contract the
    // array.
    {
        array[] <- 1;
    }
 
    return array;
}
 
// An array of somewhat random elements.
int array[] = {5, 23, 0, 4, 5, 12, 6, 85, 4, 23, 4, 3, 7, 4, 5, 2, 2};
 
// This gets the indices of all the even elements in the array via an array,
// and then adds one to the resultant elements. This makes all the elements
// in the array odd.
array[GetEvenIndices(array)] += 1;

Size Modification

As all FizzFuzz arrays are dynamic-length, it is relatively easy to query and change the size of the array. These all involve the variable name followed by brackets, which is simply as follows:

array[];

This notation indicates to the compiler that a size-related operation will take place. Simple using the above syntax of identifier[] will return the size of the array. That is, the total number of elements in the array. Assigning a value to this will alter the size of the array to that value. The notation, as described, is below.

array[] = value;

If arraysize > value, then then elements in array from arraysize to arraysize-value+1 are deleted. If arraysize < value, then value new elements are created, and the values from arraysize+1 to arraysize+value are filled with null. If arraysize = value, then nothing in the array changes.

Contraction and Expansion

Array contraction and expansion are special types of operation that increase and decrease the size of the array compared to the current size, which is contrasted to assignment. Contraction decreases the size of the array by a given amount, and expansion increases the size of the array by a given amount. The syntax is below:

Array Contraction: array[][:({+ | -} : position)] <- amount
Array Expansion:   array[][:({+ | -} : position)] -> amount[:fill]

Where:

  • array is the array being expanded or contracted.
  • + and - indicate right contraction/expansion and left contraction/expansion, respectively. By default, it contracts to the left.
  • position is the position in the index to contract or expand. If not defined, it defaults to -1.
  • amount is the amount of indices to be contracted or expanded. If contraction is being performed, then if amount > arraysize, it is set such that amount = arraysize.
  • fill is an optional value to be inserted in the new positions. If not provided, then fill = null.

Contraction

Contractions removes indices from the array, shortening the size of the array and deleting their values. By default, contraction removes a certain amount of elements from the end of the array. By using the variations provided by the syntax above, though, inner portions of the array can be removed. These removals are either left-directed or right-directed. If the position being removed is ±1, then it doesn't matter if it's left-directed or right-directed. All elements from ±1 to ±amount will be removed and deleted. If |amount - |position|| ≤ 0 (that is, if position is within amount distance of the beginning or end of array), and the direction is on the relevant side of the array (That is, on the left side if position is closer to 1, and on the right if position is closer to -1), then all from ±1 to ±amount will be removed.

If the above conditions aren't supplied, so that position is in the middle of the list relative to amount, then the deletion of elements from the array depends on whether it's left-directed or right-directed. If it's left-directed, then the values from position and the amount - 1 positions towards the first element are removed. If it's right-directed, then the values from position and the amount - 1 positions towards the last element are removed.

Expansion

Expansion adds a given amount of elements to the array, which increases the size of the array. As with contraction, expansion defaults to working on the last element of the array, but in the case of expansion it adds to it. Using the variations prescribed in the above syntax, the array can be expanded elsewhere, and have the direction changed. In a right-directed expansion, amount indices will be added after position. In a left-directed expansion, the indices will be added before position. If the value for fill is defined, then that value will be added in the new positions. If not, then null will be added.

Rotation

Arrays can be rotated, meaning that elements are either shifted to the left or right by a given amount. The notation for this is as follows:

array[][:(i1..i2)] << amount
array[][:(i2..i2)] >> amount
  • array is the array being rotated.
  • amount is the amount of shifts performed on the array. amount = amount mod arraysize.
  • i1 and i2 are an optional subarray to be rotated.

Operations Over Arrays

Operations can be applied to entire arrays, meaning that the operation will be applied to each element in the array.

array #= operand
array = array # operand
array = operand # array
value = array # operand
value = operand # array
  • array is the array being operated over.
  • operand is the value operating over the array.
  • #= and # is the operator.
  • value is a value the resultant array can be assigned to.

The limited case presented below is equivalent to the code that follows it:

int array[] = {1, 2, 3, 4, 5};
const int value = 5;
 
// Operation over an array, where @ is an arbitrary operation.
array @= value;
 
for(int i = 1; i <= array[]; i ++)
{
    array[i] = array[i] @ value;
}

The above code would result in the array int array being equal to:

{5, 10, 15, 20, 25}

See Also

Personal tools