How do I get an array slice of an ArrayList in Java? Specifically I want to do something like this:
ArrayList<Integer> inputA = input.subList(0, input.size()/2);
// where 'input' is a prepouplated ArrayList<Integer>
So I expected this to work, but Java returns a List - so it's incompatible. And when I try to cast it, Java won't let me. I need an ArrayList - what can I do?
In Java, it is good practice to use interface types rather than concrete classes in APIs.
Your problem is that you1 are using ArrayList (probably in lots of places) where you should really be using List. As a result you created problems for yourself with an unnecessary constraint that the list is an ArrayList.
This is what your code should look like:
List input = new ArrayList(...);
public void doSomething(List input) {
List inputA = input.subList(0, input.size()/2);
...
}
this.doSomething(input);
1 - Based on your comments, "you" was actually someone else ... who set this problem in an interview question. It is possible that this was actually a trick question, designed to see how you would cope with creating a (real) slice of an ArrayList that was a assignment compatible with ArrayList.
Your proposed "solution" to the problem was/is this:
new ArrayList(input.subList(0, input.size()/2))
That works by making a copy of the sublist. It is not a slice in the normal sense. Furthermore, if the sublist is big, then making the copy will be expensive.
If you are constrained by APIs that you cannot change, such that you have to declare inputA as an ArrayList, you might be able to implement a custom subclass of ArrayList in which the subList method returns a subclass of ArrayList. However:
It would be a lot of work to design, implement and test.
You have now added significant new class to your code base, possibly with dependencies on undocumented aspects (and therefore "subject to change") aspects of the ArrayList class.
You would need to change relevant places in your codebase where you are creating ArrayList instances to create instances of your subclass instead.
The "copy the array" solution is more practical ... bearing in mind that these are not true slices.
I have found a way if you know startIndex and endIndex of the elements one need to remove from ArrayList
Let al be the original ArrayList and startIndex,endIndex be start and end index to be removed from the array respectively:
al.subList(startIndex, endIndex + 1).clear();
If there is no existing method then I guess you can iterate from 0 to input.size()/2, taking each consecutive element and appending it to a new ArrayList.
EDIT: Actually, I think you can take that List and use it to instantiate a new ArrayList using one of the ArrayList constructors.
Although this post is very old. In case if somebody is looking for this..
Guava facilitates partitioning the List into sublists of a specified size
List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
List<List<Integer>> subSets = Lists.partition(intList, 3);
This is how I solved it. I forgot that sublist was a direct reference to the elements in the original list, so it makes sense why it wouldn't work.
ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
Related
I have a class which always holds four objects:
class Foo<E> {
Cow<E> a, b, c, d;
}
I want to be able to iterate over them, so ideally I'd like to use an array:
class Foo<E> {
Cow<E>[] cows = new Cow<E>[4]; // won't work, can't create generic array
}
I don't want to use a list or a set since I want there to always be 4 Cow objects. What's the best solution for me?
If you want to preserve the genericity, you will have to reimplement something similar to a list and I don't think it is worth it.
You said:
The first is that you can add and remove elements to and from a list.
Well you can create an unmodifiable list:
List<E> list = Collections.unmodifiableList(Arrays.asList(a, b, c, d));
The second is that I'm creating a quadtree data structure and using a list wouldn't be too good for performance. Quadtrees have a lot of quadrants and using lists would decrease performance significantly.
First you can initialise the list to the right size:
List<E> list = new ArrayList<>(4);
Once you have done that, the list will only use a little bit more memory than an array (probably 8 bytes: 4 byte for the backing array reference and another 4 byte for the size).
And in terms of performance an ArrayList performs almost as good as an array.
Bottom line: I would start by using a list and measure the performance. If it is not good enough AND it is due to using a list instead of an array, then you will have to adapt your design - but I doubt that this will be your main issue.
Use a generic ArrayList and simply have methods to insert values into your object, and do checks inside those methods, to make sure you don't end up having more than 4 Cow objects.
I will suggest creating a bounded list. Java does not have an inbuilt one however you can create a custom one using Google collections or use the one in Apache collections. See Is there a bounded non-blocking Collection in Java?
Use Collection instead of array:
List<Cow<E>> cows = new ArrayList<>(); // in Java 7
Or
List<Cow<E>> cows = new ArrayList<Cow<E>>(); //Java 6 and below
More information will show why it is IMPOSSIBLE to have arrays whit generics. You can see here
Cow<E>[] cows = (Cow<E>[])new Cow[4];
or
Cow<E>[] cows = (Cow<E>[])new Cow<?>[4];
I'm trying to make a variable offsets which equals ((2,1),(2,-1),(1,-2)) through which I can iterate and get the X,Y coordinates for each position.
In python, I would just use a list of lists. I thought I would be able to do this in Java, too, but it seems much more difficult to do so with this language...
I though maybe int[] offsets would work, but no dice, apparently. Then, as it's a list of lists (not just a list), I tried int[][] offset and eclipse still thought I was a moron.
What am I missing? Or am I just making this harder than it needs to be, and there's actually some really simple thing you'd suggest instead of a list of lists?
The best idea would be to use Point
Point point = new Point(1,4);
List<Point> points = new ArrayList<Point>();
Another way is to use list of lists. Not recommended. Not object oriented
List<List<Integer>>
Alternatively you can create your version of Point class. For example an object which will have one axis inside
class AxisX{
private List<Integer>
}
And put it inside another object
class Coordinates{
private List<AxisX>
}
from what's written here, it looks like you're trying to access list members with array syntax.
In java, collections and arrays have completely different syntax.
arrays are indexed with [], collections such as lists use methods.
so to get the i'th element of the j'th list
list.get(j).get(i);
the first get call returns the list at the i'th index of list
the second get call, returns the j'th element of the inner list.
though for this case, I'll second #Tom_G and suggest using something like a point object
then you only need one list, the point handling x, y coordinates in a single object.
if you will use this in something related to serialization and remote data transfer, try using the implementer classes of List, and not List itself (while declaring your variable), so not to get stuck in the middle, like
ArrayList<ArrayList<Integer>> ....
because the Collections framework interfaces dont extend the Serializable interface
maybe this helps, becuase i lived a horrible experience because i didnt notice this from the start
Is this bad practice?
ArrayList<ArrayList<ArrayList<Double>>> list = new ArrayList<ArrayList<ArrayList<Double>>>();
It is a three-dimensional matrix based on ArrayList. Doesn't look nice, but that's how we have to write it.
An alternative could be:
List<List<List<Double>>> list = new ArrayList<List<List<Double>>>();
which is a bit shorter and usually OK as in most cases your just interested in the interface methods.
So if you need a resizable threedimensional matrix data structure, then this is a clean approach.
This is not necessarily bad practice. It's just "unreadable". Have a bit of patience, in the upcoming Java 7 you're allowed to omit the cruft in specific generic types when constructing the parameterized type:
List<List<List<Double>>> list = new ArrayList<>();
This is called type inference.
As of now, if you can live with compiler warnings, you can also just do so:
List<List<List<Double>>> list = new ArrayList();
It would probably be a good idea to create a new class to handle the behavior you are trying to accomplish. I would create a class that uses an private ArrayList<...> (favor delegation over inheritance) and create necessary methods. If anything it should make things easier to read and understand.
yes. most likely your code is better off with double[][][]
Well, do you need to have a List whose elements are Lists whose elements are Lists? We have no idea what it is you are trying to accomplish unless you tell us.
However, using ArrayList directly rather than List is indeed a bad practice.
Depends on how you intend to use this. Perhaps you could encapsulate the two dimensional list and end up with a List<TwoDimensionalList<Double>>. Presumably it would have operations such as TwoDimensionalList.get(int i, int j) to get an element in the jth position of the ith list.
edit: if it's not a list of two dimensional lists, but rather a three dimensional list, then of course you want a ThreeDimensionalList. (and if your list's dimensions are fixed, you could implement this internally with a single array(list) where element (i,j,k) is located at position i*dim1 + j*dim2 + k*dim3).
At the least, naming it more expressively, something like 3dList, would help.
Preferred, for me, is to write a custom encapsulation of 2D/3D list, as others have suggested above.
How do I get an array slice of an ArrayList in Java? Specifically I want to do something like this:
ArrayList<Integer> inputA = input.subList(0, input.size()/2);
// where 'input' is a prepouplated ArrayList<Integer>
So I expected this to work, but Java returns a List - so it's incompatible. And when I try to cast it, Java won't let me. I need an ArrayList - what can I do?
In Java, it is good practice to use interface types rather than concrete classes in APIs.
Your problem is that you1 are using ArrayList (probably in lots of places) where you should really be using List. As a result you created problems for yourself with an unnecessary constraint that the list is an ArrayList.
This is what your code should look like:
List input = new ArrayList(...);
public void doSomething(List input) {
List inputA = input.subList(0, input.size()/2);
...
}
this.doSomething(input);
1 - Based on your comments, "you" was actually someone else ... who set this problem in an interview question. It is possible that this was actually a trick question, designed to see how you would cope with creating a (real) slice of an ArrayList that was a assignment compatible with ArrayList.
Your proposed "solution" to the problem was/is this:
new ArrayList(input.subList(0, input.size()/2))
That works by making a copy of the sublist. It is not a slice in the normal sense. Furthermore, if the sublist is big, then making the copy will be expensive.
If you are constrained by APIs that you cannot change, such that you have to declare inputA as an ArrayList, you might be able to implement a custom subclass of ArrayList in which the subList method returns a subclass of ArrayList. However:
It would be a lot of work to design, implement and test.
You have now added significant new class to your code base, possibly with dependencies on undocumented aspects (and therefore "subject to change") aspects of the ArrayList class.
You would need to change relevant places in your codebase where you are creating ArrayList instances to create instances of your subclass instead.
The "copy the array" solution is more practical ... bearing in mind that these are not true slices.
I have found a way if you know startIndex and endIndex of the elements one need to remove from ArrayList
Let al be the original ArrayList and startIndex,endIndex be start and end index to be removed from the array respectively:
al.subList(startIndex, endIndex + 1).clear();
If there is no existing method then I guess you can iterate from 0 to input.size()/2, taking each consecutive element and appending it to a new ArrayList.
EDIT: Actually, I think you can take that List and use it to instantiate a new ArrayList using one of the ArrayList constructors.
Although this post is very old. In case if somebody is looking for this..
Guava facilitates partitioning the List into sublists of a specified size
List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
List<List<Integer>> subSets = Lists.partition(intList, 3);
This is how I solved it. I forgot that sublist was a direct reference to the elements in the original list, so it makes sense why it wouldn't work.
ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
I am getting very frustrated because I cannot seem to figure out why Collections shuffling is not working properly.
Lets say that I am trying to shuffle the randomizer array.
int[] randomizer = new int[] {200,300,212,111,6,2332};
Collections.shuffle(Arrays.asList(randomizer));
For some reason the elements stay sorted exactly the same whether or not I call the shuffle method. Any ideas?
Arrays.asList cannot be used with arrays of primitives. Use this instead:
Integer[] randomizer = new Integer[] {200,300,212,111,6,2332};
Collections.shuffle(Arrays.asList(randomizer));
The same rule applies to most classes in the collections framework, in that you can't use primitive types.
The original code (with int[]) compiled fine, but did not work as intended, because of the behaviour of the variadic method asList: it just makes a one-element list, with the int array as its only member.
Chris' answer is correct.
As i said in a comment on Chris' answer, your underlying array will change appropriately unless the arraylist needs to grow, and the list creates a new one and copies items into it.
You may want to keep a reference to the list and iterate over that after the Arrays.asList call, and not iterate over the array after that, iterate over the List instead.