Ways to do a 2 dimensional array in java? - java

I want to store 2 dimensional values i.e. B-1, C-2, D-3, etc.
Any suggestions on the classes or interfaces that can be used?

There are three basic types of multidimensional arrays:
Fixed. Think of a chess board, which is always 8x8 (variants notwithstanding). But this can also mean something that is variable but fixed upon instantiation;
Sparse. arrays where there are lots of empty space between values. Spreadsheets typically fit this description but what is and isn't sparse is typically a subjective judgement; and
Dense. The opposite of sparse. Most or all possible values are used.
Java doesn't have a native multidimensional array type. Java has arrays of arrays, which isn't quite the same thing. For example, this is legal Java:
int arr[][] = new int[] {
new int[3],
new int[4],
new int[5]
};
Fixed arrays can be done this way but it can be awkward. It's often easier to use a single dimensional array with an object wrapper:
public class Chessboard {
public final static DEFAULT_X = 8;
public final static DEFAULT_Y = 8;
public final static DEFAULT_SIZE = DEFAULT_X * DEFAULT_Y;
private final int x;
private final int y;
private final int size;
private final Piece squares[];
public Chessboard() {
this(DEFAULT_X, DEFAULT_Y);
}
public Chessboard(int x, int y) {
if (x < 2) {
throw new IllegalArgumentException("x (" + x + ") must be 2+");
}
if (y < 2) {
throw new IllegalArgumentException("y (" + y + ") must be 2+");
}
this.x = x;
this.y = y;
size = x * y;
pieces = new Piece[size];
}
public Piece get(int x, int y) {
return pieces[y * this.x + x];
}
public Piece get(String xy) {
// eg 'h3' => (7,2)
return get(xy.charAt(0) - 'a', xy.charAt(1) - '0');
}
// etc
}
This can of course be done with arrays of arrays instead.
Sparse arrays tend to be implemented in Java with maps:
public class Sparse2DArray<T> {
public final static int MAX_X = 8192;
public final static int MAX_Y = 8192;
private final Map<String, T> array = new HashMap<String, T>();
private final Pattern XY = Pattern.compile("^([A-Za-z]+)([0-9]+)");
public T get(int x, int y) {
if (x < 0 || x >= MAX_X) {
throw new IllegalArgumentException("x (" + x + ") must be 0 to " + (MAX_X-1));
}
if (y < 0 || y >= MAX_Y) {
throw new IllegalArgumentException("y (" + y + ") must be 0 to " + (MAX_Y-1));
}
return array.get(x + "," + y);
}
public T get(String xy) {
Matcher m = XY.matcher(xy);
if (!m.matches()) {
throw new IllegalArgumentException("xy (" + xy + ") must be letters followed by digits");
}
String s = m.group(1).toUpperCase();
int multiplier = 1;
int x = 0;
for (int i=s.length()-1; i>=0; i--) {
x += (s.chartAt(i) - 'A') * multiplier;
multiplier *= 26;
}
int y = Integer.valueOf(m.group(2));
return array.get(x, y);
}
// etc
}
You can also do this by constructing an N-dimensional key class to use as the map key. It would need the appropriate equals() and hashCode() methods defined and would probably be a cleaner solution but the above will work.
Obviously if you were going to store every value of a 100x100 array in the sparse array class there would be an overhead (as all maps have overheads). This brings in the dense array. The sparse array only stores values where values are set. The dense array stores a value for every possible key (within the specified range).
Also the dense array is similar to the fixed array but not quite the same. Fixed arrays are hard to extend once created (well, it's an expensive operation so it's generally not allowed) whereas dense arrays might be built to be extended, like you could use them for a spreadsheet and extend the max X and Y values are the user uses more and more cells so you define a rectangle encompassing all used values.

If you're looking to do a spreadsheet-type application (deduced, possibly wrongly, from the spring-framework tag and the B-1/C-2 names), sparse arrays are probably the way to go.
Colt has one such implementation.
I answered a similar question here.

I am assuming you need a data structure in Java to store these values.
You could define a 2D array in Java using the following syntax.
String[][] strArr = new String[5][5]; //defines a 5*5 String array
String[][] strArr2 = new String[1][2]; //defines a 1*2 String array
Please note that the arrays can hold values of only 1 datatype. The specific items can be dereferenced using something like
System.out.println(strArr2[0][1]);
For your specific example, you could also use java.util.Map class and store the data as key-value pairs but this requires the "keys" to be unique. e.g.,
Map<String,Integer> keyval = new HashMap<String, Integer>();
keyval.put("B",1);
keyval.put("C",2);
keyval.put("D",3);
keyval.put("D",4); //wrong. will overwrite the previous entry.

I guess what you need is a Map of ArrayLists:
HashMap<String, ArrayList<YourClass>> map;
This way B-1 would be map.get("B").get(1);

Related

Java, Creating an object vector that should have n zeros in it's array after compilation

This is kind of hard but I will try to make my question as clear as possible.
So I'm working on a project that deals with operations on vectors. I have different classes for different dimensions: Vector3D, Vector5D and VectorND. So I have interface and abstract class that describe methods like Sum, Subtraction etc. And for result of operation I create a new object Vector where I put coordinates after sum/subtraction etc. So here is the part of code as an example:
interface sample
{
Vector Sum(Vector vec);
Vector Subtraction(Vector vec);
int Product(Vector vec);
boolean Compare(Vector vec);
String ToString();
}
abstract class Vector implements sample
{
int[] coordinates;
public Vector (int[] coordinates)
{
this.coordinates=coordinates;
}
protected abstract Vector resVec();
public Vector Sum(Vector vec)
{
Vector result = resVec();
if (this.coordinates.length == vec.coordinates.length)
{
for (int i = 0; i< vec.coordinates.length; i++)
{
result.coordinates[i] = this.coordinates[i] + vec.coordinates[i];
}
}
else
{
throw new ArithmeticException("Can't sum vectors of different length");
}
return result;
Here is have protected abstart Vector resVec(); - method that creates new vector with length that depends on dimension of vectors that we operate with.
Example of realization for Vector3D:
class Vector3D extends Vector
{
public Vector3D(int n1,int n2,int n3)
{
super(new int[]{n1,n2,n3});
}
public Vector3D resVec()
{
Vector3D resVec = new Vector3D(0,0,0);
return resVec;
}
So here I create a new vector with length 3 and fill it with zeros. I need to create same vector for VectorND. Like this:
class VectorND extends Vector
{
public VectorND(int...n)
{
super(n);
}
public VectorND resVec()
{
VectorND resVec = new VectorND();
return resVec;
}
Any ideas how I can pass not declared number of zeros? Or maybe any idea of different implementation? Thanks!
Within the resVec() method, you can populate an array of 0s and then pass it to your Vector super constructor. Since your super constructor takes an array of ints, you could do something like this:
public VectorND resVec(int n)
{
int[] coordinates = new int[n];
Arrays.fill(coordinates, 0);
VectorND resVec = new VectorND(coordinates);
return resVec;
}
Foremost you could make use of generics since you would get problems as soon you need float or double for a vector type.
public interface Vector<T extends Number>{
T getX();
void setX(T x);
// [...]
T length();
T lengthSquared();
// [...]
To your problem, it can be solved by adding a helper variable which contains the dimension amount and than process the math operations as algorthm / loop. This way the amount of dimension don't matter anymore and you also avoid issues like divide by zero.
this is a excample for a matrix .. but the aproche is the same:
public final void multiply(float factor) {
// in your case it would be getDimension() or something
for(int i = 0; i < getRows()*getColumns();++i){
m[i]*=factor;
}
}
Oh and I know this advice is hard for java developer but don't over engineer it otherwise you will waste preformence.
The values of arrays are automatically defaulted.
int[] ints = new int[4]; // Filled with 0
double[] doubles = new double[5]; // Filled with 0.0
boolean[] booleans = new boolean[6]; // Filled with false
String[] strings = new String[7]; // Filled with null
I am not entirely sure about your classes, but for a multi-dimensional matrix-like class one only needs one version. The values can be stored in a linearized array by using a calculated index.
public class DoubleMatrix {
final int[] sizes;
final double[] values;
public DoubleMatrix(int... sizes) {
this.sizes = Arrays.copyOf(sizes, sizes.length); // Or sizes.clone()
int valueCount = 1;
for (int size : this.sizes) {
assert size > 0 : "Every given size must be at least 1.";
valueCount *= size;
}
values = new int[valueCount];
}
public int dimesion() {
return sizes.length;
}
public double get(int... is) {
int i = index(is);
return values[i];
}
// new DoubleMatrix(2, 3, 4).set(3.14259, 0, 1, 2); // 24 values in 3D
public void set(double x, int... is) {
int i = index(is);
values[i] = x;
}
The setter is a bit unconventional placing the value first because of the var-args is.
The linearisation from several indices to an index into the values array:
private int index(int... is) {
assert is.length == sizes.length: "Wrong number of indices.";
int singleI = 0;
for (int dim = 0; dim < sizes.length) {
if (0 > is[dim] || is[dim] >= sizes[dim]) {
throw new IndexOutOfBoundsException();
}
if (dim > 0) {
singleI *= sizes[i - 1];
}
singleI += is[i];
}
}
(I am not sure the index calculation is correct.)
Instead of asserts throwing runtime exceptions (IllegalArgumentException) would be better.
Of course if get and set were protected you could make a child class without var-args, and have a public get(int i, int j) for a DoubleMatrix2D.

Hash Codes for Floats in Java

I have a class with two float variables and hashCode method (without equals in current code snippet):
public class TestPoint2D {
private float x;
private float z;
public TestPoint2D(float x, float z) {
this.x = x;
this.z = z;
}
#Override
public int hashCode() {
int result = (x != +0.0f ? Float.floatToIntBits(x) : 0);
result = 31 * result + (z != +0.0f ? Float.floatToIntBits(z) : 0);
return result;
}
}
The following test
#Test
public void tempTest() {
TestPoint2D p1 = new TestPoint2D(3, -1);
TestPoint2D p2 = new TestPoint2D(-3, 1);
System.out.println(p1.hashCode());
System.out.println(p2.hashCode());
}
returns same values:
-2025848832
In this case I can't use my TestPoint2D within HashSet / HashMap
Can anyone suggest how to implement hashCode in this case or workarounds related to this?
P.S.
Added one more test:
#Test
public void hashCodeTest() {
for (float a = 5; a < 100000; a += 1.5f) {
float b = a + 1000 / a; // negative value depends on a
TestPoint3D p1 = new TestPoint3D(a, -b);
TestPoint3D p2 = new TestPoint3D(-a, b);
Assert.assertEquals(p1.hashCode(), p2.hashCode());
}
}
And it is passed that proves that
TestPoint2D(a, -b).hashCode() == TestPoint2D(-a, b).hashCode()
I would use Objects.hash():
public int hashCode() {
return Objects.hash(x, z);
}
From the Javadoc:
public static int hash(Object... values)
Generates a hash code for a sequence of input values. The hash code is generated as if all the input values were placed into an array, and that array were hashed by calling Arrays.hashCode(Object[]).
This method is useful for implementing Object.hashCode() on objects containing multiple fields. For example, if an object that has three fields, x, y, and z, one could write:
These auto-generated hashcode functions are not very good.
The problem is that small integers cause very "sparse" and similar bitcodes.
To understand the problem, look at the actual computation.
System.out.format("%x\n", Float.floatToIntBits(1));
System.out.format("%x\n", Float.floatToIntBits(-1));
System.out.format("%x\n", Float.floatToIntBits(3));
System.out.format("%x\n", Float.floatToIntBits(-3));
gives:
3f800000
bf800000
40400000
c0400000
As you can see, the - is the most significant bit in IEEE floats. Multiplication with 31 changes them not substantially:
b0800000
30800000
c7c00000
47c00000
The problem are all the 0s at the end. They get preserved by integer multiplication with any prime (because they are base-2 0s, not base-10!).
So IMHO, the best strategy is to employ bit shifts, e.g.:
final int h1 = Float.floatToIntBits(x);
final int h2 = Float.floatToIntBits(z);
return h1 ^ ((h2 >>> 16) | (h2 << 16));
But you may want to look at Which hashing algorithm is best for uniqueness and speed? and test for your particular case of integers-as-float.
according to the java specification, 2 objects can have the same hashCode and this doesnt mean they are equal...
the probability is small but exist...
on the other hand is always a good practice to override both equals and hashcode...
As I understand the problem, you expect a lot of symmetrical pairs of points among your keys, so you need a hashCode method that does not tend to give them the same code.
I did some tests, and deliberately giving extra significance to the sign of x tends to map symmetrical points away from each other. See this test program:
public class Test {
private float x;
private float y;
public static void main(String[] args) {
int collisions = 0;
for (int ix = 0; ix < 100; ix++) {
for (int iz = 0; iz < 100; iz++) {
Test t1 = new Test(ix, -iz);
Test t2 = new Test(-ix, iz);
if (t1.hashCode() == t2.hashCode()) {
collisions++;
}
}
}
System.out.println(collisions);
}
public Test(float x, float y) {
super();
this.x = x;
this.y = y;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (x >= 0) ? 1 : -1;
result = prime * result + Float.floatToIntBits(x);
result = prime * result + Float.floatToIntBits(y);
return result;
}
// Equals omitted for compactness
}
Without the result = (x >= 0) ? 1 : -1; line it is the hashCode() generated by Eclipse, and counts 9802 symmetrical point collisions. With that line, it counts one symmetrical point collision.

Looking for a method in java to input (x,y) to an array on every iteration

I'm looking for adding a point (x,y) on every instance of an array call in java
This is what i'm trying to do
declare an array like
int [] weight = new int[100];
i'm looking to add values in the next step
weight.add(3,4);
weight.add(5,6);
The idea what i'm looking for is when i do an iteration something like this
for(int i =0;i< weight.length;i++)
print "Weight"+i+ "has"+ weight[i]
it should print
Weight 0 has (3,4);
I would create a class for each point which contains an x, and y coord... using code something like...
class Point{
public Point(int x, int y){
this.x = x;
this.y = y;
}
}
Then instead of making an array of ints, make the array of Points...
something like...
//create array of points size 100
Point [] weight = new Point[100];
//add point to array
int i = 0; //set this to the index you want the point at
weight[i] = new Point(0, 0); //add whatever point you want to index i
//then you can loop through your array of points and print them out
for (int i = 0; i < weight.length; i++){
System.out.println("Weight " + i + " has (" + weight[i].x + "," + weight[i].y + ");\n"
}
Abstracting your x and y coordinates into a Point class is a better design in my opinion. It will help you keep track of your data better in your mind when you program. Furthermore, you can add methods to your point class such as double distance(Point other) to return the distance between two points...
Create a private inner class Point as:
private static class Point {
int x;
int y;
//...........
}
Then, for each x, y pair create a point object and put it in weight.

Java: Cache results of computation?

I'm writing a program to calculate a value that is a measure of the similarity between two objects. The comparison is commutative, so compare(a, b) == compare(b, a).
The program's output to the console is a matrix of all results. However, since the matrix has each comparison twice ((a, b) and (b, a)), I'd like to save time by only calculating it once. What is the best way to cache these results?
Rough example of what the output looks like:
a b c
a 0 20 9001
b 20 0 333
c 9001 333 0
It sounds like you're already caching the results really - in the matrix. Just compute one "triangle" of the matrix and fill in the rest from that:
// Compute one triangle
for (int i=0; i < size; i++)
{
for (int j=0; j <= i; j++)
{
matrix[i][j] = computeValue(i, j);
}
}
// Now mirror it
for (int i = 0; i < size; i++)
{
for (int j = i + 1; j < size; j++)
{
matrix[i][j] = matrix[j][i];
}
}
As others have mentioned, you should just calculate one side of the triangle. You don't hove to copy it or even allocate space for it either. Just transform your x and y coordinates into a single index, and you can have an array that's a little over half the size of the full square matrix. eg:
class SymmetricMatrix {
private final double[];
/**
* #param size the size of one dimension of the matrix. eg: 3 for a 3x3 matrix.
*/
SymmetricMatrix(int size) {
matrix = new double[index(size) + 1];
}
private index(int x, int y) {
if (x > y) {
int tmp = x;
x = y;
y = tmp;
}
// now x <= y
i = (y * y + y) / 2 + x;
}
public double get(int x, int y) {
return matrix[index(x, y)];
}
public void set(int x, int y, double value) {
matrix[index(x, y)] = value;
}
}
This example uses double values, but you can easily adjust that (or even make it generic, if you want to use objects).
To fill it in:
SymmetricMatrix matrix = new SymmetricMatrix(size);
for (int y = 0; y < size; y++) {
for (int x = 0; x <= y; x++) {
matrix.set(x, y, /* value */);
}
}
Calculate only one triangle, and make an access function like
get(int x, int y) {
if (x > y) { return matrix[x][y] };
return matrix[y][x];
Looks like you don't need it for this task but if you have an expensive function and need to cache the result there is a very good thread safe method here:
http://www.javaspecialists.eu/archive/Issue125.html
You need to be rather careful with caching results of methods like compareTo and equals.
If you have N array instances you potentially need to cache N^2 comparison results. (This is of course application dependent ...)
Also, if your application creates and discards large numbers of (matrix) instances, then you may end up with lots of entries in the cache, resulting in garbage retention problems. You can mitigate this with weak references, but they make garbage collection significantly slower.
If I was doing this, I'd first profile the application to determine if the compareTo and equals methods are really bottlenecks. Then if they were, I'd consider using something other than caching to speed up the methods; e.g. storing a lazily computed hash with each array could speed up equals.

Compare elements of the same array

I have problem with comparing the value of array elements.
e.g. I wanted to compare the value of index 0 and index 2, and index 1 to index 3 and so on.
With the code below I suppose to get the result of numOfdifferentShape is 2 but I get 3.
How can I solve this problem? :-(
int numOfdifferentShape=0;
myArray = {40.0, 40.0, 40.0, 40.0, 80.0, 40.0, 40.0, 40.0}
for (int a=0; int a<myArray.size(); a=a+2)
{
for (int b=a+2; b<myArray.size; b=b+2)
{
if (!(myArray.get(a).equals(myArray.get(b) && myArray.get(a+1).equals(b+1)))
numOfdifferentShape++;
break;
}
}
There are several syntax errors in this code, but since TofuBeer has already pointed them out in the comments, I'll move on the the design and logic.
Going from the code, I'm assuming you don't have much experience with Java, and perhaps not with programming at all. So I'm going to go slowly here. I hope you aren't insulted by my explanations.
You say you are trying to find out how many of the objects which you are storing (as two ints) in your array are equal. To do this, you have to keep track of what unique objects you have already seen. Then you compare each object the list of unique objects and, if it doesn't match any of them, add it to the list. This is the basic algorithm.
Now, have you noticed that I keep using the word "object" in my description? When that happens, it usually means you should be making a class. I would make a simple one like this, holding the two integers:
class Box { // or whatever the objects are called
private final int height;
private final int width;
public Box(int h, int w) {
height = h;
width = w;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
#Override
public boolean equals(Object other) {
if (!(other instanceof Box))
return false;
Box b = (Box) other;
return b.height == height && b.width == width;
}
#Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + this.height;
hash = 97 * hash + this.width;
return hash;
}
}
Try to understand what each part of this code does (especially if this is actually your homework). Once you've got it, move on to the next part: doing the calculation that you were trying to do.
Let's say you have an array of Boxes, like this:
Box[] boxes = {
new Box(40, 40), new Box(40, 40), new Box(80, 40), new Box(40, 40)
};
(I can't tell if you're using an array or a list, so I'm just picking one to demonstrate.)
I already gave the algorithm for finding the number of unique items, so I'll show you how I would write it:
List<Box> unique = new ArrayList<Box>();
for (Box box : boxes) {
if (!unique.contains(box)) { // this is why I implemented equals() and hashCode()!
unique.add(box);
}
}
int numOfDifferentShape = unique.size();
This is much easier than trying to keep track of two ints for each object, plus it has the advantage that you can't get your array indices confused.
You could do this even more easily with a Set. It would look something like this:
Set<Box> boxSet = new HashSet<Box>();
for (Box b : boxes)
boxSet.add(b);
int numOfDifferentShape = boxSet.size();
Note that these last two snippets use features from Java 1.5, so I don't know if you've run into them before.
Does this make things clearer?
for (int i = 0; i < (myArray.size() - 2); ++i)
{
if (myArray[i] != myArray[i + 2])
++numOfdifferentShapes;
}
You have two loops, your description suggests you only want one.
You need to do bounds checking - do you want the n+2 to wrap to the start to the start of the array when it exceeds the length?
I think you have a parentheses problem. You wrote:
if (!(myArray.get(a).equals(myArray.get(b) && myArray.get(a+1).equals(b+1)))
when I think you mean:
if (!(myArray.get(a).equals(myArray.get(b)) && myArray.get(a+1).equals(b+1))
Also, in the same line, instead of:
equals(b+1)
don't you mean
myArray.get(b+1)
I have array list e.g.
{40,40,80,20,40,40} I wanted to
compare the elements. Even number of
index (e.g. index 0, index 2, index 4
etc) represents Height of an object
and Odd number of Index (e.g. index 1,
index 3 ec) represent Width of an
object. So, with the code above,
Object 1 (index 0 and 1).
Why not make an array of a Dimension class, something like this:
public class Dimension
{
private final int width;
private final int height;
public Dimension(final int w,
final int h)
{
width = w;
height = h;
}
public int getWidth()
{
return (width);
}
public int getHeight()
{
return (height);
}
}
then do a for loop something like this:
for(int i = 0; i < array.length; i += 2)
{
final Dimension a;
final Dimension b;
a = array[i];
b = array[i + 1];
// compare a.getLength() to b.getLength()
// or
// compare a.getWidth() to b.getWidth()
}
It is usually a bad idea to try and be "tricky" - saying even ones are with and odd ones are length is being tricky... bad idea IMO.

Categories

Resources