2D Matrix Equivalent of ArrayList

So I thought that it might be a good idea to try to make what is stated in the title. It has an initial size of 1x1 and can expand as much as you like. I figured it to be more convenient that having “String[][] matrix = new String[1][1];” and having to provide dimensions from the get go. Anyway, the code is obviously not perfect, feel free to use it and tell me if I’ve done anything wrong or hideously impractical.


public class ExpandableMatrix<T> {
	private T[][] data;
	private boolean locked = false;
	@SuppressWarnings("unchecked")
	public ExpandableMatrix(){
		data = (T[][]) new Object[1][1];
	}
	public T get(int x,int y){
		try{
			return data[x][y];
		}catch(Exception e){
			return null;
		}
	}
	public void fill(T object){
		for(int x = 0; x < getWidth();x++){
			for(int y = 0; y < getHeight();y++){
				put(object, x,y);
			}
		}
	}
	public ExpandableMatrix<T> expand(int newWidth, int newHeight) {
		if(locked){
			new Exception("Matrix cannot be expanded, it is locked.").printStackTrace();
			return this;
		}
		T[][] newData = newMatrix(newWidth, newHeight);
		
		if(newWidth  < getWidth() || getHeight() > newHeight){

			try{
				this.data = getSection(0,0,newWidth, newHeight);
			}catch(Exception e){
				for(int x = 0; x < newWidth; x++){
					for(int y = 0; y < newHeight;y++){
						newData[x][y] = get(x,y);
					}
				}
				this.data = newData;
			}
			return this;
		}

		for(int x = 0; x < data.length;x++){
			System.arraycopy(data[x],0, newData[x], 0, data[x].length);
		}
		this.data = newData;
		return this;
	}
	public void put(T object, int x, int y){
		if(x < 0 || y < 0)
			throw new IllegalArgumentException("X and Y must be positive");
		if(x > data.length  || y > data[0].length){
			expand(x,y);
		}
		data[x][y] = object;
	}
	@SuppressWarnings("unchecked")
	private T[][] newMatrix(int width, int height){
		return (T[][]) new Object[width][height];
	}
	
	public T[][] getSection(int x, int y, int width, int height){
		if(isValidPosition(x,y) || isValidPosition(x + width, y + height))
			throw new IllegalArgumentException("Unable to get section, section invalid");
		
		T[][] newData = newMatrix(width, height);
		for(int x1 = x;x1 < x + width; x1++){
			for(int y1 = y; y1 < y + height;y1++){
				newData[x1 - x][y1 - y] = get(x1,y1);
			}
		}
		return newData;
	}
	public boolean isValidPosition(int x, int y){
		return (x < 0 || x > data.length || y < 0 || y > data[0].length);
	}
	public void clear(){
		data = newMatrix(1,1);
	}
	public void lock(){
		locked = true;
	}
	public void remove(int x, int y){
		data[x][y] = null;
	}
	public T[][] asMatrix(){
		return data;
	}
	public int getWidth(){
		return data.length;
	}
	public int getHeight(){
		return data[0].length;
	}
}


there is a bug in put()

should be:


   public void put(T object, int x, int y){
      if(x < 0 || y < 0)
         throw new IllegalArgumentException("X and Y must be positive");
      if(x >= data.length  || y >= data[0].length){
         expand(x + 1,y + 1);
      }
      data[x][y] = object;
   }

and isValidPosition

should be:


   public boolean isValidPosition(int x, int y){
      return (x >= 0 && x < data.length && y >= 0 && y < data[0].length);
   }

or the method should be called isInValidPosition and the > should be >= then (like in put())

for optimization you could store in the outer loops a reference to

array[x]

and use this in the inner loops, but of course it depends on your matrix size and usage frequency if that makes sense and since you are using getters and setters in the loops i think it’s not very time critical code :wink:

further, in the expand() method i would copy the area of Math.min(newWidth, getWidth()) and Math.min(newHeight, getHeight()) and remove the try catch. this way you can handle the case when newWidth > getWidth but newHeight < getHeight() for example.

in getSection() you could replace the inner loop with a System.arraycopy()

and so on :wink:

EDIT: damn how can i use the array index operator in normal text without getting this list thing?

What’s wrong with [icode]List<List>[/icode]?