2
\$\begingroup\$

I have this multidimensional array that generalizes vectors and matrices:

com.github.coderodde.util.MultidimensionalArray.java:

package com.github.coderodde.util;
/**
 * This class implements a multidimensional array.
 * 
 * @author Rodion "rodde" Efremov
 * @version 1.6 (Nov 13, 2022)
 * @since 1.6 (Nov 13, 2022)
 */
public final class MultidimensionalArray<E> {
 private final int[] dimensions;
 private final E[] storage;
 
 public MultidimensionalArray(int dimension1, int... otherDimensions) {
 dimensions = new int[1 + otherDimensions.length];
 
 dimensions[0] = checkDimension(dimension1);
 
 for (int i = 0; i < otherDimensions.length; i++) {
 dimensions[i + 1] = checkDimension(otherDimensions[i]);
 }
 
 storage = (E[]) new Object[multiplyDimensions()];
 }
 
 public E get(int... coordinates) {
 checkCoordinates(coordinates);
 return storage[convertCoordinatesToIndex(coordinates)];
 }
 
 public void set(E element, int... coordinates) {
 checkCoordinates(coordinates);
 storage[convertCoordinatesToIndex(coordinates)] = element;
 }
 
 private void checkCoordinates(int... coordinates) {
 if (coordinates.length < dimensions.length) {
 throw new IllegalArgumentException(
 "The number of coordinates is too small: " 
 + coordinates.length 
 + ". Must be " 
 + dimensions.length 
 + ".");
 }
 
 if (coordinates.length > dimensions.length) {
 throw new IllegalArgumentException(
 "The number of coordinates is too large: " 
 + coordinates.length 
 + ". Must be " 
 + dimensions.length 
 + ".");
 }
 
 for (int i = 0; i < dimensions.length; i++) {
 checkCoordinate(coordinates[i], dimensions[i]);
 }
 }
 
 private void checkCoordinate(int index, int limit) {
 if (index < 0) {
 throw new IndexOutOfBoundsException(
 "Coordinate is negative: " 
 + index 
 + ". Must be at least zero (0).");
 }
 
 if (index >= limit) {
 throw new IndexOutOfBoundsException(
 "Coordinae is too large: "
 + index
 + ". Must be at most "
 + (limit - 1)
 + ".");
 }
 }
 
 private int convertCoordinatesToIndex(int... coordinates) {
 checkCoordinates(coordinates);
 int index = 0;
 int multiplier = 1;
 
 for (int i = dimensions.length - 1; i >= 0; i--) {
 index += multiplier * coordinates[i];
 multiplier *= dimensions[i];
 }
 
 return index;
 }
 
 private int multiplyDimensions() {
 int ret = dimensions[0];
 
 for (int i = 1; i < dimensions.length; i++) {
 ret *= dimensions[i];
 }
 
 return ret;
 }
 
 private static int checkDimension(int dimensionCandidate) {
 if (dimensionCandidate < 1) {
 throw new IllegalArgumentException(
 "Dimension too small: "
 + dimensionCandidate
 + ". Must be at least 1.");
 }
 
 return dimensionCandidate;
 }
}

com.github.coderodde.util.Demo.java:

package com.github.coderodde.util;
public final class Demo {
 
 public static void main(String[] args) {
 MultidimensionalArray<Integer> arr =
 new MultidimensionalArray<>(2, 3, 4);
 
 for (int i = 0; i < 2; i++) {
 for (int j = 0; j < 3; j++) {
 for (int k = 0; k < 4; k++) {
 arr.set(100 * i + 10 * j + k, i, j, k);
 }
 }
 }
 
 for (int i = 0; i < 2; i++) {
 for (int j = 0; j < 3; j++) {
 for (int k = 0; k < 4; k++) {
 System.out.println(arr.get(i, j, k));
 }
 }
 }
 }
}

com.github.coderodde.util.MultidimensionalArrayTest.java:

package com.github.coderodde.util;
import org.junit.Test;
import static org.junit.Assert.*;
public final class MultidimensionalArrayTest {
 
 @Test
 public void setAndGet() {
 MultidimensionalArray<Integer> arr = 
 new MultidimensionalArray<>(2, 3, 5);
 
 arr.set(1, 1, 2, 0);
 arr.set(2, 0, 0, 4);
 
 assertEquals(Integer.valueOf(1), arr.get(1, 2, 0));
 assertEquals(Integer.valueOf(2), arr.get(0, 0, 4));
 }
 
 @Test(expected = IllegalArgumentException.class)
 public void throwsOnTooManyCoordinates() {
 MultidimensionalArray<Integer> arr =
 new MultidimensionalArray<>(3, 2, 4, 5);
 
 arr.get(0, 1, 1, 2, 0);
 }
 
 @Test(expected = IllegalArgumentException.class)
 public void throwsOnTooLittleCoordinates() {
 MultidimensionalArray<Integer> arr =
 new MultidimensionalArray<>(3, 2, 4, 5);
 
 arr.get(0, 1, 1);
 }
 
 @Test(expected = IndexOutOfBoundsException.class)
 public void throwsOnTooSmallCoordinate() {
 MultidimensionalArray<Integer> arr =
 new MultidimensionalArray<>(3, 2, 4, 5);
 
 arr.get(0, 1, 1, -1);
 }
 
 @Test(expected = IndexOutOfBoundsException.class)
 public void throwsOnTooLargeCoordinate() {
 MultidimensionalArray<Integer> arr =
 new MultidimensionalArray<>(3, 2, 4, 5);
 
 arr.get(0, 2, 1, 0);
 }
}

Critique request

As always, I would like to hear anything that comes to mind.

asked Nov 13, 2022 at 6:51
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$
  • I am missing exposed information about dimension sizes.
  • multiplyDimensions could be just called length, possibly public too, although it would be redundant information if you expose dimension sizes
  • Cool thing to have would be to pass initializer function to constructor - function, that accepts coordinates of all dimensions and returns instance of the object. Then constructor loops over the whole array and fills it using this function.
  • That leads to possibility of creating immutable version of this class, missing set method.
  • I would consider using functional approach and replacing foreaches (not the multi-dimensinal ones), some of your cycle code would be a lot nicer and shorter.
answered Nov 13, 2022 at 9:08
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.