Java: 2D array of arraylists? - java

I am working on a sudoku solving program and I need an arraylist that holds the numbers 1 thru 9 for each of the squares on the 9x9 board. Each of these arraylists correspond to the possible numbers that could go in that square, if a number can not go in that square, it is removed from the list.
I want to be able to pull up the arraylist of the current square it is working on, like for example if I wanted to remove the number 7 from the arraylist corresponding to square (3,5)
arrayOfLists[3][5].remove(Integer.valueOf(7));
However I can't figure out how to do this. When I try to create the array I am getting this error on the line where I declare my array of arraylists
Cannot create a generic array of ArrayList
Here is my code:
//create arraylist
ArrayList<Integer> nums = new ArrayList<Integer>();
//fill arraylist with numbers 1-9
for (int i = 1; i < 10; i++) {
nums.add(i);
}
//create 9x9 array of arraylists
ArrayList<Integer>[][] array = new ArrayList<Integer>[9][9];
//fill each element of array with arraylist of numbers 1-9
for(int i = 0; i<9; i++){
for(int j = 0; j<9; j++){
array[i][j] = nums;
}
}
}
Am I doing this incorrectly or is it not possible to create an array of arraylists? If it is not possible, how should I do this then?

Anytime I see a list of lists, alarm bells start ringing. The situations where you actually want such a thing are rare indeed, and this is not one of them.
You've got a fixed board consisting of 9 fixed squares, columns and rows, each position of which may take a number 1-9.
Use an array for all of these concepts, because they are fixed in size and you need direct access to each element - collections offer no benefit and would be a hindrance. Use logic (possibly sets) to ensure numbers are used only once in each zone.

Use a bit field instead of an array list. That is, use an integer where bits 1-9 represent the possibilities of the numbers. Testing, adding, removing a single number is O(1), and it has a fixed memory size. Encapsulate the integer in its own object that knows the operations.

A few things:
1) In your for loop, array[i][j] = nums; This is going to result in the same object in each element of the array. If you call remove() on one element of the array, it's going to affect all the others. You want to build a separate list object for each element.
2) Program to interfaces; declare nums as a List as opposed to ArrayList.
3) Use a List of Lists as opposed to any array of Lists.
List<List<List<Integer>>> list = new ArrayList<List<List<Integer>>>();
for(int i = 0; i<9; i++){
List<List<Integer>> row = new ArrayList<List<Integer>>();
for(int j = 0; j<9; j++){
List<Integer> nums = new ArrayList<Integer>();
for (int k = 1; k < 10; k++) {
nums.add(i);
}
row.add(nums);
}
list.add(row);
}
// You can still get an element by index
int x = list.get(3).get(1).remove(6);
But this is kind of unwieldy. You might want to consider writing a class that represents the board. That way you'll at least have operations that better abstract this.

You could completely remove the use 2d stuff and keep a single list by giving each square a unique number from 1...81. So if you are working with 3,5 cell that means it's the 9*2+5 = 23rd item in the list. That will greatly simplify the list manipulation. You could use a single method to give the unique cell index given the (3,5) kind of reference

OK, I'm going to post this as an answer since it seems to work for me and I haven't yet seen any pitfalls.
private static class IntegerArrayList extends ArrayList<Integer> {
IntegerArrayList () { super(); }
IntegerArrayList (Collection<? extends Integer> c) { super(c); }
IntegerArrayList (int initialCapacity) { super(initialCapacity); }
}
Now you can say something like
IntegerArrayList[][] array = new IntegerArrayList[9][9];
and elements like array[1][2] will inherit all the ArrayList methods (array[1][2].remove(something) works fine). I made the class private static thinking you could nest it in some other class if that's the only place you'll use it, but you can make it public if you like. Also, I copied all three constructors from ArrayList; you could eliminate unneeded ones but I don't see a compelling reason to.
I think the issue is that new ArrayList<Integer>[9][9] is prohibited because it would create an array that wouldn't do type checking (because of "type erasure"). But I think adding your own non-generic type that inherits from ArrayList<Integer> restores the type safety.
But I'm not a generic expert, and it wouldn't surprise me if someone more knowledgeable than I spots a problem with this solution. But it seemed to work fine for me, with no compiler warnings about unchecked type stuff or anything.
(P.S. I'm posting this as a possible general solution to a problem that gets asked a lot. But in reality, for this particular problem, I might just use a fixed-size array of boolean instead of an ArrayList, like others, or I might even do bit-diddling on integers if speed is a real issue.)

Related

Why do I get unexpected behaviour when I use Arrays.fill() on an array of array lists?

I know it is not a good idea to mix up collections and arrays, but I am not getting why exactly I am getting this error.
Say,
ArrayList<Integer>[] x = new ArrayList[2];
Arrays.fill(x, new ArrayList<>());
x[0].add(1);
Why does x evaluate to ArrayList[2] { [1], [1] } now even though I am just filling index 0 with that value?
This works fine however,
ArrayList<Integer>[] x = new ArrayList[2];
for (int i = 0; i < n; i++) {
x[i] = new ArrayList<Integer>();
}
Arrays.fill(x, new ArrayList<>());
x[0].add(1);
x evaluates to ArrayList[2] { [0], [] }
What exactly causes this anomaly in the first Arrays.fill approach?
Arrays.fill(x, new ArrayList<>());
This is misleading and doesn't do what you want.
Specifically, it does this:
It creates a new ArrayList instance. One instance. Just the one.
It then takes your array of ArrayLists, which is, of course, an array of references. It's an address book with addresses to houses, not a block of houses.
It then fills the entire addressbook with the same one address. There is still just one house. You've only made a single ArrayList.
Thus, you now have an array, where each 'slot' in the array is pointing at the exact same arraylist. Add an integer to x[0] and the x[1].size() will now return 1 as well.
The fix?
Well, you said it. Stop with this silly crud of mixing the two concepts. More generally, you cannot use fill here.
UPDATE: But there is setAll:
Arrays.setAll(x, idx -> new ArrayList<Integer>()); does what you want: It invokes the thing after the array for every 'slot' in your array.
Here's a simple rule:
If you want Y objects to exist, then show me how new Something() is being run at least Y times. If you can't make a plausible case, guess what. You don't have Y objects.
In your fill based code, I count precisely 1 new .... invocation, and there is no plausible explanation available as to why somehow that one invocation is run as many times as you want (and indeed, that is the explanation: It isn't). Thus: Yup. That code doesn't do what you wanted.

Java: remove a range of indices from a list

Consider a linked list of strings I got from somewhere
LinkedList<String> names = getNames();
Now, I want to remove the first k elements from the list. Currently, I'll do it this way:
for (int i = 0 ; i < k ; i++) {
names.removeFirst();
}
Is there some way to do it more efficiently and to instead call something like:
names.removeRange(0, k);
Note that I prefer not to construct a whole new list using sublist(), as for small k values, popping k times would be even more efficient than constructing the new list
Maybe Something like this :
names.subList(0, k).clear();
this is more efficient but doesn't release memory according to sublist it's just a view:
names.sublist(k, names.size());

Create empty array without using List<object>

If I want to create an "unlimited" array I know I can use a list (There is a lot of information on this and other forums)
But what if I don't want to make a list? Is there another way?
Because I want to use a float array in another function and it's kind of a hassle to use a list in this case.
This is what I wrote so far with the listing
List<Float> listfloat = new ArrayList();
listfloat.add((float)0.1); //example
listfloat.add((float)1.2);
float data[]= new float[listfloat.size()];
for(int i = 0; i < listfloat.size(); ++i)
{
data[i] = listfloat.get(i);
}
return data ;
But I would prefer something like this
float data[]; //unknown size
for(i=0 ; i< sizeiwant; i++)
{
data[i] = mydata;
}
return data ;
I know that it will work! I just want to optimise my coding =)
Thank you for reading =)
There are 2 ways you can do this:
You could convert a list to an Array using list.ToArray()
You could dynamically resize the array by changing the size of the array every time you add an element to the array. Here is how you would do that:
//initialize array of size 10.
int[] array=new int[10];
//make copy of array
int[] arrayCopy=array.clone();
//expand array size by 1
array=new int[array.length+1];
//give value to new array index
array[array.length-1]=0;
//copy values from 'arrayCopy' to array
for(int x=0;x<arrayCopy.length;x++){
array[x]=arrayCopy[x];
}
Hope this helped.
With the information you provided I would recommend to use an Array and create a method that is called when your array is full and returns a copy of the original array with more space in this way is you are kind of simulating dynamic size allocation.
Arrays in java are fixed-size, so your second piece of code is never going to work.
If you want a data type that can resize, you should use an ArrayList. On the other hand, there are times when using primitive array like a float[] is quicker and more convenient.
As a result, the need to convert between List<Float> and float[] in the way you do it in the first block of code is fairly common, and there is no way to do it in one line (unless you use an external library).
I advise writing a utility method to do the conversion
public static float[] listToArray(List<Float> list) {
int size = list.size();
float[] temp = new float[size];
for (int i = 0; i < size; i++)
temp[i] = list.get(i);
return temp;
}
(This method could be improved, as it has poor performance for a LinkedList where get is linear).
Annoyingly, you need 8 methods like this for the 8 primitive types, and 8 methods to do the conversions in the other direction. As things stand at the moment, there is no way to write generic code over primitive types, so code duplication like this is common.

Common elements of muiltiple arrays but not using Lists

Is there a way i could return in an array the common elements of 2 or more arrays? I know having some of the methods under lists could do it but is there a way to do it by only using arrays? I made my own get and length btw since i am creating a an array called OrderedIntList.
Example would be:
1,3,5
1,6,7,9,3
1,3,10,11
Result: 1,3
I tried this and it outputs the common elements between two arrays and not all.
I know there's something wrong but i do not how to make it work like it suppose to work :(
//returns the common elements of inputted arrays
public static OrderedIntList common(OrderedIntList ... lists){
int[] list = new int[10];
for(int x = 1; x <= lists.length -1; x++){
for(int q = 0; q < lists[0].length()-1; q++) {
for(int z = 0; z < lists[x].length(); z++) {
if (lists[0].get(q)==lists[x].get(z)){
list[q] = lists[0].get(q);
}
}
}
}
OrderedIntList newlist = new OrderedIntList(list);
return newlist;
}
This can be an easy algorithm to solve it...
1) Instantiate an instance variable of type array called
"commonElements" pointing to the elements of the first Array. At the
beginning these are your common elements.
2) Create a method call getCommonElements(int[] commonElements,
int[] newList). This method manipulates the commonElements array to leave
it with only the common elements between the two. (p.s Use a temporary
array to achieve this if you find it easier)
3) Iterate over all the arrays present in "lists" starting from the
second array.
4) call the method at point 2 for each array .
All the difficult part for you it's to implement a method that given 2 arrays finds the common elements!
You can use
org.apache.commons.collections.CollectionUtils.intersection(java.util.Collection a, java.util.Collection b)
to get the intersection of two lists (elements presents in both lists)
And to pass your array as a Collection: java.util.Arrays.asList(Object[] a);
But working on arrays is tedious, at best. You should consider why you don't want to use a Collection...
As a partial answer, you're probably doing too much work by fully reimplementing an OrderedIntList the way you're doing, since ArrayList and friends already come with sorting baked in via the Collections class.
import java.util.Collections;
public class OrderedIntList extends ArrayList<Integer> {
#override // to effect sorted inserts
public void add(Integer i) {
this.add(i);
Collections.sort(this);
// done.
}
}
Wanting to do this for pure arrays is a nice exercise, but then you'll be better of implementing sorting properly with a quick sort (you can't websearch for a java implementation of that without getting a million results) or an insert sort (equally websearchable), and follow the same recipe.
any time you push a number into the array:
guess where the number goes (although that's optional),
insert the number,
resort your array if you know your guess wasn't perfect.

Set rank of array at runtime

I was wondering what the simplest way would be to implement an array who's rank is specified at runtime.
The example I am working on stores a array of boolean values for lattice points, and I want the user to be able to chose how many spatial dimensions the model uses at runtime.
I've looked at the Array.newInstance() method:
dimensionOfSpace = userInputValue; // this value comes from GUI or whatever
int latticeLength = 5; // square lattice for simplicity
int[] dimensions = new int[dimensionOfSpace];
for(int i = 0; i < l.length; i++) l[i] = length;
Object lattice = Array.newInstance(boolean.class, dimensions);
But accessing these values in any sort of way seems to require horribly slow methods such as recursively using Array.get until the returned value is no longer an array, i.e. using isArray().
Am I missing an obvious solution here? I would love to be able to access the values in a way similar to foo[i][j][k].
Looks like what you are looking for is for some way to declare how many dimensions an array has at runtime. I don't know how this could be done using a multidimensional ArrayList, or any multidimensional structure where you have to specify the dimensionality at compile time.
The only answer I see is to use a simple linear array wrapped in a class that converts multidimensional coordinate to and from the its position in the underlying array. This is basically how languages such as C stores multidimensional arrays by using one contiguous chunk of memory.
The code would look something like this:
import java.util.*;
class MultiArray<T>{
private int[] dimensions;
private Object[] array;
public MultiArray(int ... dimensions){
this.dimensions=dimensions;
//Utils.product returns the product of the ints in an array
array=new Object[Utils.product(dimensions)];
}
public void set(T value, int ... coords){
int pos=computePos(coords);
array[pos]=value;
}
public T get(int ... coords){
int pos=computePos(coords);
return (T)(array[pos]);
}
private int computePos(int[] coords){
int pos=0;
int factor=1;
for (int i=0;i<coords.length;i++){
pos+=factor*coords[i];
factor*=dimensions[i];
}
return pos;
}
}
class Main{
public static void main(String args[]){
MultiArray<Integer> m=new MultiArray<Integer>(new int[]{5,4,3});
Random r=new Random();
for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
for(int k=0;k<3;k++)
m.set(r.nextInt(),i,j,k);
for(int i=0;i<5;i++){
for(int j=0;j<4;j++){
for(int k=0;k<3;k++)
System.out.print(m.get(i,j,k)+" ");
System.out.println("");
}
System.out.println("\n");
}
}
}
class Utils{
public static int product(int...a){
int ret=1;
for (int x:a) ret*=x;
return ret;
}
}
Checkout Java Collections. It contains a class called ArrayList that grows in size as needed.
One dimensional
List<Boolean> a = new ArrayList<Boolean>();
Two Dimensional
List<List<Boolean>> b = new List<List<Boolean>>();
Three Dimensional
List<List<List<Boolean>>> c = new List<List<List<Boolean>>>();
And you'd access the item as c.get(i).get(j).get(k) instead of c[i][j][k] as in a 3d array. Or even better, wrap it in your own Class, and use a get() method there. So it becomes:
c.get(i, j, k);
Edit:
To have a multi-dimensional list of depth N, remove the Boolean type indictor and simply create lists as
List level1 = new ArrayList();
List level2 = new ArrayList();
List level3 = new ArrayList();
level1.add(level2);
level2.add(level3);
and so on..
I'm going to use the term 'rank' to mean the 'number-of-dimensions' in your array. So a vector has rank 1, a matrix has rank 2 and so on. You've already accepted an answer that by your own admission is not quite what you want. Here's an alternative to settling for less:
Recall that computer memory is essentially linear and that what a compiler does when it gives you arrays is actually take care of transforming an index expression into a linear address. This is simplest to think about if you assume that all arrays are in contiguous memory, not always true. Suppose that you make a declaration such as ARRAY_OF_TYPE[10][10][10], ie it has 1000 elements. Then the element at position [3][5][4] is (my arrays are indexed from 1 not 0 -- change the sums that follow if you want to) at location baseAddress+354*size_of_element_of_TYPE.
I expect you know where I'm going on this by now ...
At run time your program prompts for a list of integers from the user. Each integer specifies the size of one of the dimensions of the array, the number of integers specifies the rank of the array. Your program does some multiplications and you allocate a vector of the right length. OK, you have to write the indexing and de-indexing functions, but these should be fairly straightforward.
et voila you have an array whose rank is established at run time.
I did a quick google search for "java tensor" which came up with DJEP, could that be something which fits your bill?

Categories