# ⌛⌛⌛ `N`

-dimensional array¶

Place your code into a file named **NdArray.java** in the directory Round8/ndarray. Remember to
pull task material from `student_template_project`

.

In this task you should implement a fixed `N`

-dimensional array as a generic container class
`NdArray<E>`

. The idea is that e.g. an `NdArray`

objecd created as
`new NdArray<String>(2, 5, 4)`

would represent a 3-dimensional `String`

array whose dimensions
have sizes 2, 5 and 4. To be more precise, the first dimension size would be 2, the second 5 and
third 4. In similar manner `new NdArray<Double>(3, 3, 3, 3, 3)`

would create a 5-dimensional
`Double`

array whose all 5 dimensions have size 3.

The word “fixed” used in the beginning means that the parameters given to the constructor fix the number and sizes of the array dimensions; they cannot be changed later.

The generic class `NdArray<E>`

should have the following public features:

Inherits the abstract class

`AbstractCollection<E>`

from the Java class library.This requires us to implement the member functions

`size`

and`iterator`

described below.Inheriting the class will in effect make

`NdArray`

a more or less fully featured Java container container class.`NdArray`

objects could e.g. be processed with streams by using the inherited member function`stream()`

.

Constructor

`NdArray(Integer firstDimLen, Integer ...furtherDimLens)`

that receives one or more dimension sizes.The parameters list the sizes of dimensions 1…``N``.

`firstDimLen`

is the size of the first dimension and`furtherDimLens`

lists the sizes of dimensions 2…``N`` (if there is more than one dimension).The first dimension size is received separately in order to force the constructor to receive at least one parameter.

Therefore the overall number of dimensions

`N`

= number of parameters = 1 + number of`furtherDimLens`

parameters (size of that array).

Each dimension size must be non-negative (0 is allowed).

If some dimension size is negative, throw a

`NegativeArraySizeException`

exception with a message “`Illegal dimension size dimLen.`

”, where`dimLen`

is the first negative dimension size among the parameters.

Member function

`int size()`

that returns the overall size of the array (multiplication of its dimension sizes). E.g. a 3-dimensional array with dimension sizes 2, 5 and 4 has size 2 · 5 · 4 = 20.Member function

`E get(int... indices)`

that returns the item at the array location specified by`indices`

.The number of

`indices`

must be equal to the number of dimensions`N`

.If the number of parameters is wrong, throw an

`IllegalArgumentException`

exception with a message “`The array has N dimensions but x indices were given.`

”, where`N`

is the number of dimensions and`x`

is the number of`indices`

parameters.

Each index must be legal, that is, in the interval 0…size of the corresponding dimension - 1.

If any dimension is given an illegal index, throw an``IndexOutOfBoundsException`` exception with a message “

`Illegal index i for dimension dim of length dimLen."`

”, where`i`

is the first illegal index within`indices`

, and`dim`

and`dimLen`

are the ordinal number and size of the corresponding dimension. The ordinal numbers of the dimensions are 1, …,`N`

.E.g. if we have a 3-dimensional array with dimension sizes 2, 5 and 4, the call

`get(i, j, k)`

is legal if and only if 0 ≤`i`

< 2, 0 ≤`j`

< 5 and 0 ≤`k`

< 4.

Member function

`void set(E item, int... indices)`

that stores`item`

into the array location specified by`indices`

.The

`indices`

parameters are subject to the same rules as in the`get`

function. E.g. the same exceptions are thrown in case of wrong number of indices or an illegal index.

member function

`int[] getDimensions()`

that returns an array containing the dimension sizes.The returned array has size

`N`

and the value at index`i`

tells the size of dimension (``i``+1).`NdArray`

probably maintains this kind of an array internally in order to know its dimension sizes. But note: do not return this kind of internal array directly! Create and return a new array because otherwise the function caller could corrupt internal data by modifying the array.

Implements the interface

`Iterable<E>`

(because the inherited`AbstractCollection<E>`

does).Iterater the array items in the same order as a typical way of using

`N`

nested loops where the outermost loop iterates the first dimension, the loop directly inside it iterates the second dimension, and so on.Define a suitable iterator class that implements

`Iterator<E>`

(e.g. as a private inner class).If you follow (and it is a good idea) the advice given below, the iterator can be very simple: it would suffice to maintain only information about the current iterator index in a one-dimensional table.

Implement a member function

`Iterator<E> iterator()`

that creates and returns an object of the above described iterator class.

**Advice:** one relatively simple approach to implement an `N`

-dimensional array is to store the
items into a one-dimensional array. The main challenge is then how to compute a mapping from `N`

indices to an index of the internal one-dimensional array. The basic principle is described e.g.
in this article
(follow the “row-major” order described first in the article, as that makes iteration trivial). I
do not recommend you to try to implement a “truly” multidimensional solution; it would make the
task much more complicated.

## Testing¶

You may test your implementation by using the test program given in the file `NdArrayTest.java`

and the example output given in the files `output1.txt`

, `output2.txt`

, `output3.txt`

and
`output4.txt`

. Place these files to the same directory with your code, compile the test program
e.g. as `javac *.java`

, and run the tests as `java NdArrayTest 1`

, `java NdArrayTest 2`

,
`java NdArrayTest 3`

and `java NdArrayTest 4`

. The expected outputs of these tests are given in
the files `output1.txt`

, `output2.txt`

, `output3.txt`

and `output4.txt`

.

A+ presents the exercise submission form here.