1

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?

Petefic
  • 657
  • 6
  • 14
  • 31
  • See these answers: http://stackoverflow.com/questions/11113095/how-can-i-initialize-my-generic-array, http://stackoverflow.com/questions/4549192/create-an-array-of-arrayliststring-elements – Kevin Aug 24 '13 at 00:13
  • 1
    replace the 10 element `ArrayList` with a `boolean[9]` and set those that are removed to `false` – zapl Aug 24 '13 at 00:21
  • I haven't seen this in any of the answers at those links, but I just tried `private class IntegerArrayList extends ArrayList { ... }` and declaring constructors like ArrayList's that just used `super(...)`; then I was able to use `new IntegerArrayList[9][9]` and the `ArrayList` methods worked fine on array components, e.g. `a[i][j].add(n)`. Is there any reason this approach wouldn't work? – ajb Aug 24 '13 at 00:30
  • I would use an array, not an ArrayList. – Bohemian Aug 24 '13 at 00:50

5 Answers5

1

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.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • why do you keep saying 'if' instead of 'of'? – Zoltán Aug 24 '13 at 10:18
  • @Zoltán yeah I seem to do that a lot. It's because I post pretty much exclusively using my iPhone, and too often my right thumb doesn't bend back enough to hit the "o" and hits the "I" instead. Combine that with my eyesight being crap and I don't notice the error. You asked! :) – Bohemian Aug 24 '13 at 10:32
1

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.

Tassos Bassoukos
  • 16,017
  • 2
  • 36
  • 40
  • Also, for this particular use, it seems likely that the program will want to test more than one number simultaneously. (I've never tried to write a Sudoku solver, this is just based on the thought processes I go through when I solve them myself.) For this purpose, using the bits of an integer could lead to simpler code. Good idea about encapsulating the integer. – ajb Aug 24 '13 at 16:30
0

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.

Tap
  • 6,332
  • 3
  • 22
  • 25
0

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

Dev Blanked
  • 8,555
  • 3
  • 26
  • 32
-1

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.)

ajb
  • 31,309
  • 3
  • 58
  • 84
  • `IntegerArrayList` seems like a silly way of writing `ArrayList` – Navin Dec 28 '13 at 06:44
  • @Navin You've probably missed the whole point. The point is that you **can't** write `ArrayList` because of Java's rules about generics and arrays (in particular, `new ArrayList[9][9]` is illegal). Therefore, you need another approach, and one possibility is to define a non-generic name that is, in effect, a synonym for `ArrayList`. If you don't like the name I chose, please suggest a better one. I'm not good at inventing names. But if that's your downvote, please remove it since you've misunderstood the issue. – ajb Dec 28 '13 at 18:16
  • I didn't notice that. Can't you write `ArrayList[] table = (ArrayList[])(new ArrayList>[4]);`? Only the declared type matters for generics, so this should also be type safe. – Navin Jan 01 '14 at 13:20
  • @Navin That seems to compile, although with a "uses unchecked" warning. It's probably OK, though, since this `new` doesn't create any `ArrayList` objects, and all future operations should be type-safe. I'm still not a generics expert, so there may be some nuance I'm missing. I'll keep this solution in mind if this question gets asked again in the future. – ajb Jan 01 '14 at 18:19