The problem
I have an ArrayList of ArrayLists. I am copying one over to the other, except in a different order (a rotation of the elements by 180°, but that's not important).
I have this generic code:
ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
for (int r = 0; r < 4; r++) {
for (int c = 0; c < 5; c++) {
list.get(r).set(c, "an element from the other list");
}
}
I'm arbitrarily using sizes 4 for the number of rows and 5 for the number of columns.
However, this throws an index out of bounds error, obviously because I have no dimensions for the ArrayList<ArrayList<String>>.
I know that when creating an ArrayList, you can give it an initial capacity for a constructor parameter. However, I don't know how to apply that to this:
ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
This won't compile, but this is essentially what I want:
ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>(5)>(4);
My mediocre solution
To give the matrix some dimensions before I attempted to copy the list over, I just iterated for the number of rows I wanted and added a list of size of the number of columns I wanted to each row.
I used a regular array and converted it to an ArrayList just so that the elements would have a default value of null, and so would contribute to the size.
for (int r = 0; r < 4; r++) {
// list.add( new ArrayList<String>(5) ); // doesn't work
list.add( new ArrayList<String>( Arrays.asList(new String[5]) ) );
}
So that works for setting the size, because enough elements will be added to the matrix, but it's not the preferred solution.
The question
Is there any way to set the initial dimensions of an ArrayList of ArrayLists during the initialization? Or just something different that iterating and adding null values?
This works for me:
ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>(4);
for (int r = 0; r < 4; r++) {
ArrayList<String> ls = new ArrayList<String>(5);
ls.add("" + (r + 1));
list.add(ls);
}
for (ArrayList<String> ls : list) {
System.out.println(ls);
}
Note: do not confuse ArrayList#size(), current number of elements in the collection, with ArrayList#capacity, current maximum size of the collection (which cannot be accessed).
For more info, refer to: ArrayList(int):
Constructs an empty list with the specified initial capacity.
Note that using List<List<Whatever>> you're not creating a 2D dynamic array, you're creating a dynamic list which will contains dynamic lists, thus you must initialize every list by separate and add lists (from any size) into another list, and every list would have a dynamic size (despite the values they have). There's no 2d dynamic array nor dynamic array of arrays in plain Java, unless you create such class or import it from a third party library.
Looks like this structure would suit better for your case:
String[][] stringArrayOfArray = new String[4][5];
Another very odd way (not recommended) to accomplish what you want/need would be:
List<String>[] arrayOfList = new List[4];
for (int i = 0; i < arrayOfList.length; i++) {
arrayOfList[i] = new ArrayList<String>();
}
Related
I am facing a very simple issue :
List<String> myList = new Vector<String>(10);
myList.add(5,"HELLO");
gives me ArrayOutOfBoundException : 5>0
Is there a way to specify the size of a Vector and fill the list in random order?
You're not specifying the size, you're specifying the capacity of Vector.
You could do:
List<String> myList = new Vector<String>();
for(int i = 0;i < 10; i++)
myList.add(null);
myList.set(5, "HELLO");
What you should do is forget the Vector class, since it's been outdated for over 10 years already.
If you just need fixed size and random access, you can use an array
String[] myArr = new String[10];
If you need it to be a Collection, you can use
List<String> myList = Arrays.asList(myArr);
Finally if you want to add more elements in it (Arrays.asList() returns a fixed size list) you can use
List<String> myList = new ArrayList<>(Arrays.asList(myArr));
The documentation of the add() method explicitly states:
ArrayIndexOutOfBoundsException - if the index is out of range (index < 0 || index > size())
Since your size at the moment is 0, the behaviour is as expected.
The constructor of the Vector class specifies the initial capacity, not the size of the collection.
After checking out what was said in the comments, I am removing my suggestion. It's better to stick to arrays in that case.
I have a listview.
private String[] listView2 = {"aa","aa","aa"};
int a = 0;
Int values will decide to add the number of content
So if a==2.
listView2 = {"aa","aa"};
if a==5
listView2 = {"aa","aa","aa","aa","aa"};
You're clearly familiar with array initializers where you specify the content up-front... but you can also create arrays just by specifying the length, like this:
String[] array = new String[length];
This will create an array where every element is a null reference (or the a 0, false or '\0' for numeric, Boolean or character arrays respectively). You then just need to populate it. You could do that with a loop:
String[] array = new String[length];
for (int i = 0; i < length; i++) {
array[i] = "aa";
}
Or you could use the Arrays.fill method:
String[] array = new String[length];
Arrays.fill(array, "aa");
One comment on your title though - it's worth understanding that once you've created an array, you can't actually add elements to it (or remove elements from it). The array object has a fixed size. If you do:
String[] array = new String[4];
...
array = new String[5];
then that doesn't add an element to the array - it creates a new array of length 5, and assigns a to that array to the variable array. Any other variables which still have a reference to the original array won't see any change.
If I understand you correctly this is what you want:
private String[] listView2 = new String[a];
for(int i = 0 ; i<a ; i++){
listView2[i] = "aa";
}
An array has a set number of things it can contain.
If you want to have a dynamic list that can change size, then you should probably use ArrayList<String> like this:
List<String> list = new ArrayList<String>();
for(int i = 0; i < a; i++)
{
list.add("aa");
}
Unlike arrays in other languages, eg javascript, java arrays are fixed length.
If you want to add another element to a full array, you must create another larger array, copy the elements over and assign the end element.
Don't use arrays! They are a pain. Instead use a List, which will expand in size automatically when needed.
During my search for info about multidimensional arraylist, I read that you could create a class to handle the multidimensional arraylist.
I'm doing a Android game similar to Bejeweled, and instead of using a common multidimensional grid, I guess this would be better!? I also has a list of all the sprite objects and I wonder if I can store and control all this objects with a multidimensional arraylist class?
But I'm not sure how a class would look like and how do I set and get values from the arraylists? Is there anyone who are interested to explain how it's working and show a simple code example? Thanks!
EDIT: I want to have objects in the arraylists like this example int grid[][] = new int[8][8]; but instead of integers, I want to have objects. And I wonder if it's possible to get and set values the same easy was like in the example I just showed?
EDIT 2: I have a grid 8x8 and that's why I'm using a array like [8][8], but I can only have values of type integers or booleans at each positions. I also have to use an arraylist to handle all the 64 objects that has a positions within this grid. Each object store it's position, both in the grid array and the position on the screen. I just wanted to make it a little bit simplier to handle and create a gird with multidimensional arrayList to both store the objects and have a grid? Possible or is there a better way to do this?
int size =8;
List<List<Integer>> list = new ArrayList<List<Integer>>(size);
for(int i=0; i<size; i++)
{
list.add(new ArrayList<Integer>());
}
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
Integer x = list.get(0).get(1); //access the 0,1 element
}
}
EDIT :
If you want to use a specific class. For ex: Node, you could use List<List<Node>> instead of List<List<Integer>> and then access it. You can then call any methods of the Node class as follows:
Node node = list.get(0).get(1); // access the Node at 0,1
node.getProperties();
There is no big difference between ArrayList and array.
Would say there are only 2 pros of ArrayList:
ability to dynamically change a size
adding new element at end of array, without need to look for first empty slot
And for multidimensional another pros is possibility to have different lengths for nested ArrayLists.
In Your case I think You don't need any of this so choose one You feel more comfortable, If You don't know how to make ArrayList of ArrayLists but know how to use array use them.
But just to answer Your question.
ArrayList<ArrayList<Object>> root = new ArrayList<ArrayList<Object>>();
root.add(new ArrayList<Object>());
root.add(new ArrayList<Object>());
root.add(new ArrayList<Object>());
root.add(new ArrayList<Object>());
root.get(1).set(1, Object); //puts new object at position 1,1
Object o = root.get(1).get(1); //gets object from position 1,1
With multidimensional array:
Object[][] grid = new Object[8][8];
grid[1][4] = new Object(); //set new object at position 1,4
grid[1][4].doSmth(); //calls method doSmth() of object stored at position 1,4
Object o = grid[1][4]; //gets object at position 1,4
List<List<Integer>> multiList = new ArrayList<List<Integer>>();
multiList.add(new ArrayList<Integer>());
Integer element = multi.get(0).get(0); // element at 0,0
First your start with defining your multi-dimensional arrayList
int size = 8;
List<List<YourClass>> 2dList = new ArrayList<List<YourClass>>(size);
then you initialize it
for(int rowIndex = 0; rowIndex < size; rowIndex++) {
List<YourClass> row = new ArrayList<YourClass>(size)
for(int columnIndex = 0; columnIndex < size; columnIndex++) {
row.add(new YourClass());
}
2dList.add(row);
}
now you have an sizexsize ArrayList with instances of your class
to access it:
2dList.get(rowIndex).get(columnIndex) // will return the YourClass-Object you placed there
if you want to replace the object on a certain position with another instance you need to remove the old object first:
2dList.get(rowIndex).remove(columnIndex);
2dList.get(rowIndex).add(columnIndex, newYourClass);
So, I want an array of Vector of Integer in Java.
If I put
Vector<Integer>[] matrix;
matrix = new Vector<Integer>[100];
I get cannot the compilation error
cannot create a generic array of Vector
Should I use
matrix = new Vector[100];
instead? (which gives a warning)
Or should I simply not use an array of vectors and use vector of vector instead?
Note: I don't want a Vector< Integer >, I want a Vector< Integer >[] to create a matrix of Integers without using Integer[][].
Java simply doesn't have any means to create arrays of a parameterized type without getting or suppressing a warning. So the best you can get is this:
#SuppressWarnings("unchecked")
Vector<Integer>[] anArray = (Vector<Integer>[]) new Vector<Integer>[100];
You can get around this problem if you avoid arrays entirely. I.e.:
Vector<Vector<Integer>> list = new Vector<Vector<Integer>>(100);
Or with the collection types:
List<List<Integer>> list = new ArrayList<List<Integer>>(100);
Vector<Integer> vector = new Vector<Integer>();
If you try to do something like this:
Vector<Integer> vector = new Vector<Integer>();
Vector<Integer>[] vectors = {vector};
You will get a compile error:
Cannot create a generic array of
Vector
However if you don't specify the generic type java will allow it but with a warning:
Vector<Integer> vector = new Vector<Integer>();
Vector[] vectors = {vector};
Vectors are backed by arrays, and will grow or shrink to a size sufficent to hold the element you insert into it. As such, you can pre-allocate a Vector, but you do not have to actually specify the size at create time.
// preallocated vector, which can hold 100 elements
Vector<Integer> integers = new Vector(100);
.
// default vector, which will probably grow a couple of times when adding 100 element
Vector<Integer> integers = new Vector();
A true Java array cannot grow or shrink, and it doesn't support removal of an element from a mid-point. To allocate an Array, you use
// allocate an array
Integer[] integers = new Integer[100];
Now if you want to have an "array of vectors" then you would
// array of vectors
Vector[] vectors = new Vector[100];
To create an array of generic you have to create the non-generic and cast it. You also have to initialise all the elements in the array, otherwise they will be null. :(
Vector<Integer>[] anArray = (Vector<Integer>[]) new Vector[100];
for(int i = 0; i < anArray.length; i++)
anArray[i] = new Vector<Integer>();
However, since Vector is a legacy class which was replaced by ArrayList in Java 1.2 (1998) I would use List for the interface and ArrayList for the implementation.
List<Integer>[] anArray = (List<Integer>[]) new List[100];
for(int i = 0; i < anArray.length; i++)
anArray[i] = new ArrayList<Integer>();
Another option would be to use a collection which held primitive int instead of Integer Objects. This can enhance performance if you need it.
TIntArrayList[] anArray = new TIntArrayList[100];
for(int i = 0; i < anArray.length; i++)
anArray[i] = new TIntArrayList();
To avoid type casting, consider this implementation:
Vector<Integer>[] intVectorArray;
Vector[] temp = new Vector[desiredSize];
intVectorArray = temp;
for(int i = 0;i<intVectorArray.length;i++){
hashArray[i] = new Vector<Integer>();
}
The newly created intVectorArray will inherit the generic Vector-Array type of temp to give you your desired dimensions, and the for loop will instantiate your desired datatype.
When you're ready to call Integer functions on elements of intVectorArray, you will be all set!
How can I filter an array in Java?
I have an array of objects, for example cars:
Class:
public class Car{
public int doors;
public Car(int d){
this.doors = d;
}
}
Use:
Car [] cars = new Cars[4];
cars[0] = new Car(3);
cars[1] = new Car(2);
cars[2] = new Car(4);
cars[3] = new Car(6);
Now I want to filter the array of cars, keeping only 4 doors and more:
for(int i = 0; i<cars.length; i++){
if(cars[i].doors > 4)
//add cars[i] to a new array
}
}
How should I do this?
Before I did it with a Vector:
Vector subset = new Vector();
for(int i = 0; i<cars.length; i++){
if(cars[i].doors > 4)
//add cars[i] to a new array
subset.addElement(cars[i]);
}
}
And then I would make a new array with the size of the Vector. Then I would loop over the vector again and fill the new array. I know this is a very large procedure for something simple.
I'm using J2ME.
EDIT: saw that ArrayList is not in J2ME, but based on documentation, it does have a Vector. If that Vector class is different than J2SE Vector (as this documentation indicates), then perhaps the following code would work:
Vector carList = new Vector();
for(int i = 0; i<cars.length; i++){
if(cars[i].doors > 4)
carList.addElement(cars[i]);
}
}
Car[] carArray = new Car[carList.size()];
carList.copyInto(carArray);
The most efficient way to do this--if the predicate you're filtering on is inexpensive and you're accessing it with a single thread--is usually to traverse the list twice:
public Car[] getFourDoors(Car[] all_cars) {
int n = 0;
for (Car c : all_cars) if (c.doorCount()==4) n++;
Car[] cars_4d = new Car[n];
n = 0;
for (Car c : all_cars) if (c.doorCount()==4) cars_4d[n++] = c;
return cars_4d;
}
This traverses the list twice and calls the test twice, but has no extra allocations or copying. The Vector-style methods traverse the list once, but allocates about twice the memory it needs (transiently) and copies every good element about twice. So if you are filtering a tiny fraction of the list (or performance isn't an issue, which very often it isn't), then the Vector method is good. Otherwise, the version above performs better.
If you really need a plain array as the result, I think your way is the way to go: you don't know the number of resulting elements before you filter, and you can't construct a new array without knowing the number of elements.
However, if you don't need thread-safety, consider using ArrayList instead of a Vector. It ought to be somewhat faster. Then use ArrayList's toArray method to get the array.
I can't see much wrong with your code. You could just stick with Vectors throughout though.
You could simplify the second part (where you copy the matching items into the new array) using Vector.copyInto(Object[]).
There's no direct way to remove elements from an array; its size is fixed. Whatever you do, you need to allocate a new array somehow.
If you want to avoid the minor memory overhead of allocating a Vector, another option would be to make two passes over your array. The first time, simply count the number of elements that you want to keep. Then allocate an array that size, and loop over your old array again, copying matching elements into the new array.
You can use System.arrayCopy():
Car[] cars = ...
int length = cars.length < 4 ? cars.length() : 4;
Car filter = new Car[4];
System.arrayCopy(cars, 0, filter, 0, length);
UPDATE: System.arrayCopy is available in Java ME API, unlike Vector.subList(). Thanks for the correction.
You will need to create a new array anyway.
Vector vector = new Vector(array.length);
for (int i = 0; i < array.length; i++) {
if (array[i].doors > 4) {
vector.add(array[i]);
}
}
Car[] result = new Car[vector.size()];
vector.copyInto(result);
This isn't quite efficient, though.