⌛⌛⌛ 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
anditerator
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 functionstream()
.
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 andfurtherDimLens
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 offurtherDimLens
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.
”, wheredimLen
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 byindices
.The number of
indices
must be equal to the number of dimensionsN
.If the number of parameters is wrong, throw an
IllegalArgumentException
exception with a message “The array has N dimensions but x indices were given.
”, whereN
is the number of dimensions andx
is the number ofindices
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."
”, wherei
is the first illegal index withinindices
, anddim
anddimLen
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 storesitem
into the array location specified byindices
.The
indices
parameters are subject to the same rules as in theget
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 indexi
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 inheritedAbstractCollection<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.