How to access lookup tables in classes of their own?
Hi,
I have a big lookup table in a class of its own, with the other code it exceeded the 65535 class size allowance... and what I would like to know is how to structure it so that a) I only have one instance of it, and b) the easiest way to access it?
The class header looks like this:
publicclass Flushes{
/*
** this is a table lookup for all "flush" hands (e.g. both
** flushes and straight-flushes. Entries containing a zero
** mean that combination is not possible with a five-card
** flush hand.
*/
short Flushes[] ={
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1599, 0, 0, 0, 0, 0, 0, 0, 1598, 0, 0, 0, 1597, 0, 1596,
8, 0, 0, 0, 0, 0, 0...
And was being called using: return( flushes[q] );
So how would I achieve the same thing but with the table now in its own class?
Many thanks, Ron
[1183 byte] By [
cakea] at [2007-11-26 19:52:47]

Store it in a text file, write a static method just once that will open the file, parse the file, and return the array.
Make the method cache the array too, so you don't open the file every time the method is called.
Make sure every place you need to access the table goes through that static method.
Don't name a variable the same as its classname.
Why not make a Map that only contains valid Flushes?
Map<Integer, Integer> flushMap = new HashMap<Integer, Integer>();
flushMap.put(someIndex, 9);
flushMap.put(anotherIndex, 1599);
if (!flushMap.containsKey(yetAnotherIndex))
{
System.out.println("Flush not possible with " + yetAnotherIndex);
}
Integer flushCombo = flushMap.get(someOtherIndex);
if (flushCombo != null)
{
System.out.println("Flush for " + someOtherIndex + " is " + flushCombo);
}
I don't know what your numbers mean, but the above should give you an idea. Indexes for which you had a zero in your array would return 'null' for 'get', or would return 'false' for 'containsKey'.
I didn't count into your array to see what those indexes are.
Storing the table in a separate text file and loading it into the above Map exactly once at startup is a good idea, too. Then you can have other maps for other types of poker hands that use the same code to load them--just have multiple text files.
My first answer was generic. As for the specific issue of a card-game, who wrote that short[]? And why?
What if you made a typo somewhere and accidently included an extra "0,"?
Rhetorically: How did you decide that the ordering should be the way it is?
My guess is you used some sort of math formula to create the array. Why not just put that math formula directly into your method that was returning values from the array (removing the need for an array in the first place)?
Message was edited by:
bheilers
Hi, I am going to go for the 'reading in from a text file' action as I haven't done this before. So I have been looking at all the examples and am profferring one here :) My question is that though the structure seems pretty straightforward, what is the action of the 'token' and why doesn't java recognise it?
public static int[] getIntegersFromFile(String fileName) throws IOException {
StringWriter writer = new StringWriter();
BufferedReader reader = new BufferedReader(new FileReader(fileName));
List<Integer> list = new ArrayList<Integer>();
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
writer.write(line + " ");
}
StringTokenizer tokens = new StringTokenizer(writertoString());
while (tokens.hasMoreTokens()) {
String str = tokens.nextToken();
try {
list.add(new Integer(str));
} catch (NumberFormatException e) {
System.out.println("Error '" + str + "' is not an integer.");
}
}
int[] array = new int[list.size()];
for( int i = 0; i < array.length; i++){
array[i] = list.get(i);
}
return array;
}
Anyway, I will continue to look at examples, many thanks, Ron
cakea at 2007-7-9 22:43:58 >

I think your trouble is:
StringTokenizer tokens = new StringTokenizer(writertoString());
should be (add a period):
StringTokenizer tokens = new StringTokenizer(writer.toString());
However, a faster way would be to create the list directly without the writer (assuming one integer per line):
public static int[] getIntegersFromFile(String fileName) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(fileName));
List<Integer> list = new ArrayList<Integer>();
String line;
while ((line = reader.readLine()) != null)
{
try
{
list.add(Integer.valueOf(str));
} catch (NumberFormatException e) {
System.out.println("Error '" + str + "' is not an integer.");
}
}
int[] array = new int[list.size()];
for( int i = 0; i < array.length; i++){
array[i] = list.get(i);
}
return array;
}
Even with more than one integer per line, you should parse (including tokenize/split, if needed) each line individually, rather than making a whole String using a Writer.
Or, just return the List itself, instead of making an int array. The code that would use the int[ ] could just as easily use 'get' on a List.
With flushes an int[]:
flushes[q]
would become (with flushes a List):
flushes.get(q);
And, if you have lots of zeroes, using a Map would be a better idea than a List. You will waste a lot of space with all of those zeroes. With flushes a Map, you'd still have:
flushes.get(q);
But, you'd have to check for null before using it:
int returnValue;
Integer flushValue= flushes.get(q);
if (flushValue == null)
{
System.out.println("No flush.");
returnValue = 0;
}
else
{
returnValue = flushValue.intValue();
System.out.println("Flush value: " + flushValue);
}
The println statements are just for debugging--you wouldn't need them in your final code.
1. Only one instance: Singleton pattern can be used, if I get you correctly.2. Going for a file approach is a good idea.Regards
You said in your duplicated thread that your file format would be:
0,0,1934,0,0,1454,0,0...
So, you can either:
A:
1. read one line at a time,
2. split the line on commas (look up the "split" method in the String class),
3. and convert each element of the array returned from "split" into an Integer in your Map.
or:
B:
1. Use a Scanner on your file, setting the delimiter to be a comma. Then you might not need to worry about "lines" in the file at all [look at the Scanner API for details about scanning with a delimiter other than whitespace]. Scanner will even do the checking for int and parsing for you--see hasNextInt() and nextInt(). You'll still need to create Integer objects to put into your Map, but you could use autoboxing for that if you want.
doremifasollatido - I am sorry for putting up the same post 3x, I will admit I did post it twice because I felt the title was misleading, the third was totally a mistake as I thought I was actually replying to a question on my other post, again, sorry.
Thanks for all the adive, it has been very helpful in pointing me in the right direction.
I can read in the contents of the file as a string using a scanner as below. But I am having difficulty understanding why if I change hasNext() and next() to hasNextInt() and nextInt() I get nothing?
Also, I am trying to strip out any additional spaces with the regular expression, \\s removes one and I thought that \\s* would remove any number, am I completely off on that one?
Many thanks, Ron
private static void readFile() {
try {
File file = new File("test.txt");
Scanner scanner = new Scanner(file).useDelimiter("\\s*,\\s");
while (scanner.hasNext()) {
System.out.println(scanner.next());
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
cakea at 2007-7-9 22:43:58 >

Hi,Ignore the bit about the regular expression, I realised my error... my thinking was completely off on that one :)Thanks, Ron
cakea at 2007-7-9 22:43:58 >

Ok, this now works, it wasn't before because of the way the .txt file was formatted and the two were not matching, so I have:
private static void readFile() {
List<Integer> t = new ArrayList<Integer>();
try {
File file = new File("test.txt");
Scanner scanner = new Scanner(file).useDelimiter(",\\s*");
while (scanner.hasNextInt()) {
t.add(scanner.nextInt());
//System.out.println(scanner.nextInt());
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println(t.toString());
}
Is that ok, is there a better way?
Ok, now to have a go at the hashmap...
Many thanks, Ron
Message was edited by: cake
cake
cakea at 2007-7-9 22:43:58 >

Yes, your new Scanner code looks good (I didn't actually test it, though). See how much shorter it is than your original? Scanner takes care of a lot of the details for you, and you also don't waste time/memory creating a long, unneeded String. You need to return the List t, though. Otherwise, you load it but don't store it anywhere.
For the map, you'll want to store the int value temporarily, so that you can test if it's zero before adding to the Map. You'll also need a counter (which gets incremented even if you don't add to the map).
In pseudocode:
Map<Integer, Integer> m = new HashMap<Integer, Integer>();
int counter = 0;
while (scanner.hasNextInt()) {
int val = ...; // Read one int from scanner.
if (val is not equal to zero)
{
add entry to Map with counter as key and val as value
}
counter++; // increment counter
}