简体   繁体   中英

Java: 2D array of arraylists?

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM