What is the correct way to store large static arrays in Java?
I have three arrays of floats, each consisting of about 30000 elements that I need to access from my program. The contents of the arrays will not change.
Edit: I am currently not able to access the arrays from any Java program without splitting them up into relatively small (sub 1k elements) arrays, putting them in separate methods (each limited to 64KB of bytecode) and then merging them in the program. Which seems like an abysmal solution to me.
Made a separate program that accepted the matrices on stdin and stored them in files. First row in each file is an integer representing the number of elements in the matrix, the following rows are the actual matrix elements. Not a pretty solution, but it got the job done.
public static void main(String[] args) throws IOException, ClassNotFoundException {
Scanner in = new Scanner(System.in);
float[] floatArray;
int count = in.nextInt();
float temp;
int i = 0;
floatArray = new float[count];
while (in.hasNextFloat()) {
temp = in.nextFloat();
floatArray[i] = temp;
i++;
}
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("glockVert.arr"));
outputStream.writeObject(floatArray);
}
Related
I am coming from a C++ background and I have just started learning java. I am not able to understand why do I need to provide the size of an array before compiling even though it is an object and is stored on heap?
Any examples that could help me clear up the concept are welcome.
I am not able to understand why do I need to provide the size of an array before compiling…
You don't need to provide the size before compiling. For example, the following code allows the user to provide the size at runtime:
final Scanner input = new Scanner(System.in);
System.out.print("Array size: ");
final int[] array = new int[input.nextInt()];
System.out.printf("The array size is %d.\n", array.length);
If you'd like an easy-to-resize array-like object, ArrayLists are very nice.
If you create an array
int[] ia = new int[0];
It's size cannot be changed later, so if you try to add a value, you get an out of bounds exception. If this does not work for your program, you should use an ArrayList which is an object that does not have a defined size so while terrible this code should work:
ArrayList<Integer> al = new ArrayList<Integer>();
for(int q = 0; q < 10000; q++){ //Infinitely add ints to the ArrayList
int i = 1;
al.add((Integer) i);
}
I have to write a method to write data to a file. It has to take an array of integers as a parameter and write them to a file, but I am getting an error on these lines:
Integer[] x = val.toArray(new Integer[val.size(25)]);
if (x < 0) break;
public static void writeToFile (String filename, int[] x) throws IOException {
PrintWriter outputWriter = new PrintWriter("integers.txt");
System.out.println("Please enter 25 scores.");
System.out.println("You must hit enter after you enter each score.");
Scanner sc = new Scanner(System.in);
int score = 0;
while (score < 25) {
int val = sc.nextInt();
Integer[] x = val.toArray(new Integer[val.size(25)]);
if (x < 0) break;
outputWriter.println(x);
score++; }
outputWriter.flush();
outputWriter.close();
}
There are a couple of things. First off, you are trying to do things that are not possible to do with an int. Look at the ever helpful java API when trying to use a class:
http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html
Next, if I was writing your program (which I'm not and I do not intend to), I would watch your instantiations. The array is being instantiated every loop which means that you will have a new array every time the user puts in a value. Meaning all the previous numbers are going to be lost. Also, take the integer array out of the parameter. You aren't even using it in the method.
Instantiate your array outside of the loop with a size of 25 elements:
int[] array = new int[25];
Now, you can place the items in this array every loop like this:
array[score] = val;
This places the value in the indexes 0 -> 24. It seems to me that in order to truly understand how to do this program you are going to have to have a refresher on arrays and how they work.
Finally, the computer sees this method as a sequence. So, line by line think about what is happening on your program. Ideally, this is what should be happening.
Instantiate your objects: the scanner, the array (where the ints are stored), the Print writer
give instructions to the user how to use the program.
run a loop 25 times doing this:
- scanning in an int
- placing the int into the array at the appropriate index
write the array into the file
flush the writer.
close the writer.
I'm trying to read my file in notepad using CSVReader but I cannot get it work. it says ArrayIndexOutOfBoundsException: 2 line "y[i][2]". eventhough I intiallize my array rows in 100. I'm currently new in using Java and CSVReader.
public static void main(String[] args) throws IOException {
double[][] x = new double[100][3];
double[][] y = new double[100][1];
String line[];
try{
CSVReader br=new CSVReader(new FileReader("ex2data2.txt"),',');
int i = 0;
while((line=br.readNext())!=null){
x[i][0] = Double.parseDouble(line[0]);
x[i][1] = Double.parseDouble(line[1]);
y[i][2] = Double.parseDouble(line[2]);
i++;
}
br.close();
}
catch (IOException e) {
e.printStackTrace();
}
It's completely unclear as to why you would be storing the data as you are after reading it from the file, but ...
double[][] y = new double[100][1];
This allocates an array of 100 double arrays, each with a length of 1
Here:
y[i][2] = Double.parseDouble(line[2]);
You attempt to store something at the third element of one of those 100 arrays. They aren't that large; you created them to have a length of one.
I suspect you meant to do:
y[i][0] = Double.parseDouble(line[2]);
since the only thing you're storing in the y arrays is that single value.
All that being said, this is a poor way to store these values. In general you are better served using a dynamic data structure so you don't have to worry about what the length (number of lines) of the file is. In addition, why would you need two different 2D arrays? Even a List<Double[]>, for example, would be better.
You have create
double[][] y = new double[100][1];
i.e. 100 rows and 1 column. but trying to put value at position y[i][2]. thats why you are getting ArrayIndexOutOfBoundsException. create like
double[][] y = new double[100][3];
or you can simply put value as (in this case you don't need to create 2D array given as above)
y[i][0] = Double.parseDouble(line[2]);
I got a task. The input of the Java Decathlon program is a CSV-like text file. The task is to output an XML file with all athletes in ascending order of their places, containing all the input data plus total score and the place in the competition (in case of equal scores, athletes must share the places, e.g. 3-4 and 3-4 instead of 3 and 4)
This is my cvs file:
Jana Kari;12.61;5.00;9.22;1.50;60.39;16.43;21.60;2.60;35.81;5.25.72
Eva Narun;13.04;4.53;7.79;1.55;64.72;18.74;24.20;2.40;28.20;6.50.76
Maja Hope;13.75;4.84;10.12;1.50;68.44;19.18;30.85;2.80;33.88;6.22.75
Kirke Kanda;13.43;4.35;8.64;1.50;66.06;19.05;24.89;2.20;33.48;6.51.01
I got these constants for each decathlon event
double[] A = new double[]{25.4347,0.14354,51.39,0.8465,1.53775,5.74352,12.91,0.2797,10.14,0.03768};
double[] B = new double[]{18,220,1.5,75,82,28.5,4,100,7,480};
double[] C = new double[]{1.81,1.4,1.05,1.42,1.81,1.92,1.1,1.35,1.08,1.85};
Formula for points is
Points = INT(A(B — P)^C) for track events (faster time produces a better score)
Points = INT(A(P — B)^C) for field events (greater distance or height produces a better score)
"P" is persons records (from cvs). I dont really understand how to read properly from file that it would allow me to do calculations with numbers only. Should i use two dimensional array for cvs file ? Its very confusing and im stuck.
EDIT
Well i believe for outputing later to xml file one dimensional array is better. The point of my task is code simplicity, but CVS file may be expanded to N lines so i never know how much rows it will have. I want to use number array in this code:
double[] A = new double[]{25.4347,0.14354,51.39,0.8465,1.53775,5.74352,12.91,0.2797,10.14,0.03768};
double[] B = new double[]{18,220,1.5,75,82,28.5,4,100,7,480};
double[] C = new double[]{1.81,1.4,1.05,1.42,1.81,1.92,1.1,1.35,1.08,1.85};
double PTS;
double finalscore;
for (int i = 0; i < P.length;i++ )
{
finalscore=0;
if (i == 0)
{
PTS = A[i]* Math.pow((P[i]-B[i]),C[i]);
}
else if (i == 4)
{
PTS = A[i]* Math.pow((P[i]-B[i]),C[i]);
}
else if (i == 5 || i == 9)
{
PTS = A[i]* Math.pow((P[i]-B[i]),C[i]);
}
else
{
PTS = A[i]* Math.pow((P[i]-B[i]),C[i]);
}
finalscore = finalscore + PTS;
}
System.out.println(finalscore);
}
}
Where P[] would be array first lane of number without name.
P.S it seems code above gives me result NaN when i use
double[] P = new double[]{12.61,5.00,9.22,1.50,60.39,16.43,21.60,2.60,35.81,5.272};
Yes, you have the right idea - you can use a two dimensional array. I would also recommend you create a class called Person, as this is Java programming and Java is object-oriented, but if you have not studied creating multiple classes yet, you can skip that bit and just do it with two arrays, one one-dimensional array for the names and one two-dimensional array for the numbers.
For the one-dimensional array approach
public class Person {
String name;
double[] scores;
int minutes;
int seconds;
int hundredths;
public Person(String line) {
String[] splitted = line.split(";");
name = splitted[0];
// now fill in the other fields
for(int i = 1; i < splitted.length - 1; i++) {
scores[i - 1] = Double.parseDouble(splitted[i]);
}
String times = splitted[splitted.length - 1].split("\\.");
minutes = Integer.parseInt(time[0]);
// etc. - fill in the rest
}
}
(Actually, this might be wrong, because I assumed most of the numbers are scores, but I guess they are really seconds and hundredths of a second. It doesn't really matter, unless you could have a time over one minute for those events.)
Then you need to have an array of Person objects in your other class - let's make it quite big so that it will be big enough hopefully:
Person[] array = new Person[10000];
Now have a loop, and whenever you read a line from the file you just call the constructor.
array[j] = new Person(line);
Nice approach, isn't it?
I've made a game that randomly generates mazes, the maze is stored in a 2d array.
each integer in the array represents the number of walls that cell has.
It's based on the java example here: http://rosettacode.org/wiki/Maze
To allow people to share a unique maze i'm trying to find a way to convert the array into a string or an integer that can be generated by one user, copied and then pasted into another game which will then load the same maze.
The user can select the size of the maze up to 25x25 so simply printing each value (2|16|4|20...) would be incredibly long.
If converting it to a 'code' isn't possible are there any other ways it can be done without using a file?
Store the seed for the random number generator. The seed fully determines the output of the random number generator.
Assuming you are using java.util.Random to generate the random numbers, instead of using the default constructor new Random() use
long seed = System.currentTimeMillis();
// store the seed somewhere
// so you can generate the same sequence of random numbers again
Random rng = new Random(seed);
To make a short "code" that can be given to users for sharing, you can convert the number to hex or base 36:
String code = Long.toString(seed, 36); // codes like heeho82h
If you're randomly creating the values for that array, you only need the state of the PRNG that produced those values to re-generate them. That's at the same time the biggest weakness and strength of all pseudo-random number generators.
As most PRNGs don't allow retrieving and setting the state, or have a pretty huge state (a Mersenne Twister has a few kilobyte of state internally), you may want to use the seed instead. Of course, then you must create a new PRNG (or reset an existing one) for level generation.
To make the number human-readable, you should just render it in some number base. Base 10 makes it obvious it's a number and is easiest to generate and parse. Base 16 (hexadecimal) and base 64 yield shorter, more obscure "codes". Padding it to be fixed-length regardless of the actual value is probably a good idea.
You could use Serialization concept to save the state of 2-D array and then retrieve it back using deserialization. Here is the simple Demo to save a 2-D array state and then read it back . I hope it would be of your help:
import java.io.*;
class ArraySerialization
{
ByteArrayOutputStream baos;
ByteArrayInputStream bins;
public void saveState(Object obj)throws Exception
{
baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
}
public int[][] readState()throws Exception
{
bins = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream oins = new ObjectInputStream(bins);
Object obj = oins.readObject();
oins.close();
return (int[][])obj;
}
public static void main(String[] args) throws Exception
{
int arr[][]= {
{1,2,3},
{4,5,7}
};
ArraySerialization ars = new ArraySerialization();
System.out.println("Saving state...");
ars.saveState(arr);
System.out.println("State saved..");
System.out.println("Retrieving state..");
int j[][] = ars.readState();
System.out.println("State retrieved..And the retrieved array is:");
for (int i =0 ; i < j.length ; i++ )
{
for (int k = 0 ; k < j[i].length ; k++)
{
System.out.print(j[i][k]+"\t");
}
System.out.print("\n");
}
}
}
Although it uses a random generator, it is in fact a deterministic process. You can repeat it by knowing the random seed. Just share the random seed, as mentioned by Joni. Anyway, if you want to share the data: a NxN mesh has NxN inner walls, and considering it takes 1 bit to store presence/absence of a wall, you will need NxN bits to store the maze. In this way you can store a 90x90 maze in 1kb.