Receiving IndexOutOfBoundsException when removing item from Java ArrayList - java

I have a list of values. I want to remove the list item when check box is unclicked:
ArrayList<SalesRoutes> routeList = new ArrayList<SalesRoutes>();
ArrayList<String> selectedRoutes = new ArrayList<String>();
routeList =getSalesRoute();
for (int i = 0; i < routeList.size(); i++) {
CheckBox ch = new CheckBox(this);
ch.setId(i);
ch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
if(arg0.isChecked()){
Log.i("add", routeList.get(arg0.getId()).getRouteCode());
selectedRoutes.add(routeList.get(arg0.getId()).getRouteCode());
System.out.println("----add ----" + selectedRoutes);
}else {
selectedRoutes.remove(arg0.getId());
Log.i("remove", routeList.get(arg0.getId()).getRouteCode());
System.out.println("----remove ----" + selectedRoutes);
}
}
});
}
Here I got IndexOutOfBoundsException because selectedRoutes is selected CheckBox values
selectedRoutes
[R0002]
routeList displays a list of routes on the screen. It fetches the route from a db.
Example routeList:
Route List
R0001
R0002 // selected this one ID is 1
R0003
calling remove from selectedRoutes(1).
selectedRoutes.remove(arg0.getId());
Here selectedRoutes only contains one record, which means there is no index 1.
How can I remove this?

The problem is with this section of code:
selectedRoutes.remove(arg0.getId());
Log.i("remove", routeList.get(arg0.getId()).getRouteCode());
System.out.println("----remove ----" + selectedRoutes);
You're hinging that on the (usually incorrect) assumption that the index of your route in your list of potential routes is the same as the index of your route in the list of selected routes. Instead, you'll want to get the route code of the route in your potential list of routes at that index, then iterate through your list of selected routes (which are actually just Strings containing route codes), and remove the index where the two match up. Code would look something like this:
String routeCode = routeList.get(arg0.getId()).getRouteCode();
index = -1;
for(int i = 0; i < selectedRoutes.size(); i++) {
if(routeCode.equals(selectedRoutes.get(i)) {
index = i;
break;
}
}
if(index > -1)
selectedRoutes.remove(index);
Log.i("remove", routeCode);
System.out.println("----remove ----" + selectedRoutes);

It would be much easier if you created selectedRoutes to be a collection of the same objects ArrayList<SalesRoutes> selectedRoutes. Since both collections would contain the references to the same object you could remove the object by its reference:
salectedRoutes.remove(routeList.get(arg0.getId()));

Calling ArrayList.remove(int location) will remove the object at that location in the array. It does not remove a object by it's Id value.
It appears you are adding an object to the arraylist at an index position returned by .getRouteCode()
But then you are trying to remove an object at an index position returned by .getId().
The two don't sync up.

You have mixed ArrayList.remove(int index) and ArrayList.remove(Object o).

Related

get element from ArrayList (java)

Struggling with what is probably a simple query to match and return an element in an ArrayList.
I first store a HashSet in the ArrayList because HashSet has no get method and then check the ArrayList (which contains the correct elements, strings of socket references).
List theseSocks = new ArrayList(NodeConnMaster.sockList);
System.out.println("array list contains " + theseSocks);
I then want to iterate through and find the matching ipAddress in the element and once found set a variable to the entire element, so something like -
for (int i =0; i< theseSocks.size(); i++) {
if (theseSocks.toString().contains(ipAddress)) {
int element = theseSocks.get();
System.out.println("the element is " + element);
}
}
but it appears that get needs an index position and I am trying to get based on string contents, not index.
Is there an easier way than deleting all the elements except the matching one and then returning index 0.
Or is ArrayList not the way to go.
The solution was, with SBylemans's help -
Object currentSock = null;
for (int i =0; i< theseSocks.size(); i++)
{
currentSock = theseSocks.get(i);
if (currentSock.toString().contains(ipAddress))
{
System.out.println("the element is " +currentSock);
break;
}
}
Regards
Ralph
You can use stream of Java8 for filtering required elements like:
List wantedList = theseSocks.stream()
.filter(e ->e.toString().contains(ipAddress))
.collect(Collectors.toList())
You're looping over the ArrayList and want to compare based on the String value. But looping like this will immediately also give you the index. Your loop should look something like this:
for (int i =0; i< theseSocks.size(); i++)
{
String currentSock = theseSocks.get(i);
if (currentSock.equals(ipAddress))
{
System.out.println("the element is " +currentSock);
break;
}
}
Or even with a forEach loop
for (String currentSock: theseSocks)
{
if (currentSock.equals(ipAddress))
{
System.out.println("the element is " +currentSock);
break;
}
}
The break is used to interupt the for loop once your element is found.
Additionaly, your if condition will cause a print of every element if the array contains the ipAddress you're looking for.
Edit And then when using java 8, you can also use streams as posted by others.

Add specific item from ArrayList into LinkedList Java

I have an ArrayList with lots of objects. I want to be able to add any objects into a choice of 3 different LinkedLists. A user input will select which item to add to which LinkedList by typing the index they wish to be added. This is the kind of thing i'm after, but i just can't get it to work:
public void addToRepository(int indx, int r) {
if (r == 1){ //checks to see if chosen repository 1
for (int i=0; i < itemList.size(); i++) {
i = indx;
} // ignore this it was just me playing around to see if i'd be able to get the index this way..
repo1.add(itemList.get(indx)); //adds item from "itemList" with the index that
the user input has given
//other if statements
}
}
I'm not sure this is the correct idea but it gives error "Item cannot be converted to String". If not, how can i go about doing this?
So you have
ArrayList<Item> itemList = new ArrayList<Item>();
and you are trying to do -
repo1.add(itemList.get(indx));
As per the Exception you are getting it looks like repo1 has String data. You can do one of the following things -
Use repo1.add(itemList.get(indx).toString()); OR
Change repo1 generics to include Item data instead of String

Next element using for loops java

Very rudimentary question but I have a loop e.g.
List<ObjectList> = //set of values inside.
for(Object data : ObjectList){
// how to access next element?
// current element is accesed by 'data'. I could get the index position and then increment but is there a easier way?
}
How would you get the next element/previous? I know there are iterators i can use and so on but i want to know a neat way to do it in a for loop.
You can but don't do it as the time complexity of the loop will
increase. Just use a normal loop with an int i looping variable.
If you still want to do it you can find the index this way:
int index = lst.indexOf(data);
Then index+1 is the index of the next element.
And index-1 is the index of the previous element.
Make two methods for next and pervious and pass list and element.
public static <T> T nextElement(List<T> list,T element){
int nextIndex=list.indexOf(element)+1;
return list.size()<nextIndexlist?null:list.get(nextIndex);
}
public static <T> T previousElement(List<T> list,T element){
int previousIndex=list.indexOf(element)-1;
return list.size()>previousIndexlist?null:list.get(previousIndex);
}
1)First way
for(ObjectList data : objectList){
ObjectList previousElement=previousElement(objectList,data);
ObjectList nextElement=nextElement(objectList,data);
}
2) Second way
for(int i=0;i<=objectList.size();i++){
ObjectList previousElement=objectList.size>i-1?null:objectList.get(i-1);
ObjectList nextElement=objectList.size<i+1?null:objectList.get(i+1);
}
3) Third way using iterator
Actually, your for-each isn't iterating a List. This,
List<ObjectList> = //set of values inside.
for(Object data : ObjectList){
}
Should look something like,
List<ObjectList> al = new ArrayList<>();
for(ObjectList data : al){ // <-- like so.
}
But that won't find any data until you populate the List.
Using a "normal" for-loop, this might be, what you are looking for:
List<Object> objectList = new ArrayList<>();
// add some data
for (int i = 0; i < objectList.size(); i++) {
System.out.println((i > 0) ? "previous Object: " + objectList.get(i - 1) : "No previous object, current is the first one.");
System.out.println("Current Object: " + objectList.get(i));
System.out.println((i < objectList.size()) ? "Next Object: " + objectList.get(i + 1) : "No next object, current is the last one.");
}
Key aspect is, that you have to use your loop variable (i in this case) to access your actual elements. i + 1 gives you the next element and i - 1 the previous.
I think what you is an iterator, its used like this:
List<ObjectList> list= //set of values inside.
Iterator<ObjectList> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
System.out.println(iterator.previous());
iterator.next()
}
It allows you to access the next and previous objects.
ListIterator:
There is the ListIterator which can a bit of stepping back and forth.
Mind in the code below previousIndex() yields -1 at the start.
for (ListIterator<Object> iter = objectList.listIterator(); iter.hasNext(); ) {
Object object = iter.next();
Object previous = objectList.get(iter.previousIndex()); // Might fail
Object next = objectList.get(iter.nextIndex()); // Might fail
if (iter.hasPrevious()) ... iter.previous();
}

Filter ArrayList and remove unwanted elements

I have a ArrayList that contains elements (fields are name and type). There are only two different possible types ("edu" and "ent") that I want each to be displayed in its own listview.
My idea was to create two new ArrayLists with same data and then loop through each and filter unwanted elements like this:
ListView listView_ent = (ListView) findViewById(R.id.popular_apps_list_ent);
ArrayList<DataHolder> data_ent = data;
for (int i = 0; i < data_ent.size(); i++) {
if(data_ent.get(i).getType().equals("edu")){
data_ent.remove(i);
}
}
listView_ent.setAdapter(new AppsAdapter(this, data_ent));
ListView listView_edu = (ListView) findViewById(R.id.popular_apps_list_edu);
ArrayList<DataHolder> data_edu = data;
for (int i = 0; i < data_edu.size(); i++) {
if(data_edu.get(i).getType().equals("ent")){
data_edu.remove(i);
}
}
listView_edu.setAdapter(new AppsAdapter(this, data_edu));
There are 10 elements in ArrayList, 5 of each type.
Problem is that at the end in the both listviews there are 4 same items displayed with mixed types.
Any idea what I did wrong?
1) copy the data
2) don't iterate using i and remove; use an iterator (remove method: http://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html#remove()) or start at the end of the list
something like this:
ListView listView_ent = (ListView) findViewById(R.id.popular_apps_list_ent);
ArrayList<DataHolder> data_ent = new ArrayList( data);
for (int i = data_ent.size()-1; i >= 0; i--) {
if(data_ent.get(i).getType().equals("edu")){
data_ent.remove(i);
}
}
listView_ent.setAdapter(new AppsAdapter(this, data_ent));
ListView listView_edu = (ListView) findViewById(R.id.popular_apps_list_edu);
ArrayList<DataHolder> data_edu = = new ArrayList( data);
for (int i = data_edu.size()-1; i >= 0 ; i--) {
if(data_edu.get(i).getType().equals("ent")){
data_edu.remove(i);
}
}
listView_edu.setAdapter(new AppsAdapter(this, data_edu));
Yes, assignment will just copy the value of data_ent (which is a reference) to data_edu. They will both refer to the same object. So whatever changes you make in either list, same changes will reflect in the other list as well
This is you should do :-
List<Integer> data_edu = new ArrayList<Integer>(data_ent);
or use the addAll() function of array list.
Once you remove an item from your ArrayList, the indeces all shift down. You can either add in i-- after remove, or use an iterator:
Iterator<DataHolder> i = data_edu.iterator();
while (i.hasNext()) {
DataHolder d = i.next();
if (d.getType().equals(...) {
i.remove();
}
}
Rahul is correct regarding list references, but you have another problem as well.
ListView listView_ent = (ListView) findViewById(R.id.popular_apps_list_ent);
ArrayList<DataHolder> data_ent = data;
for (int i = 0; i < data_ent.size(); i++) {
if(data_ent.get(i).getType().equals("edu")){
data_ent.remove(i);
}
}
The problem is that when you remove, you bugger your indices. You're essentially skipping items. Consider
{"edu", "edu", "ent"}
Once you take out the first item (index 0), the second edu becomes the new index 0, but you move on and check index 1.
Try using a ListIterator http://docs.oracle.com/javase/6/docs/api/java/util/ListIterator.html
hint:
ListIterator<DataHolder> entDataIterator = data_ent.listIterator();
while(entDataIterator.hasNext(){
if(/*whatever*/){
entDataIterator.remove();
}
}
In your for for loops, you may be skipping items. Let's say your list is something like that:
list = {edu, edu, ent, ent, edu}
Your index variable will be i = 0. list[i] == "edu" then you remove it, but then your list becomes:
list = {edu, ent, ent, edu}
But your index variable gets incremented and is then equals to 1. and list[1] = "ent". As you undersand you are not processing the first element of the list. You skipped indices.
Hope this is clear.
If you have commons-collections available in your project, you may as well use the filter method on CollectionUtils:
CollectionUtils.filter(your_list, new Predicate() {
#Override
public boolean evaluate(Object obj) {
return !((DataHolder) obj).getType().equals("edu");
}
});
Your remove loop is wrong. You can use this: for (int i= data_end.size - 1, i >=0, i--)
Think about feature extension later? Use more than 2 types?
The solution is very simple. Your code a filter function first
public List<DataHolder> filterBy(List<DataHolder> list, String type) {
List<DataHolder> l = new ArrayList<>();
for ( DataHolder h : list) {
if (h.getType().equals(type)) {
l.add(h);
}
}
return l;
}
Use the filter function:
List<DataHolder> eduList = filterBy(data, "edu");
listView_edu.setAdapter(new AppsAdapter(this, eduList));
List<DataHolder> entList = filterBy(data, "ent");
listView_ent.setAdapter(new AppsAdapter(this, entList));
Consider using Guava library for filtering collections:
http://www.motta-droid.com/2013/12/collections-performance-tests-in.html
In example above, filter returns new filtered collection don't affecting source collection. Maybe it's not worth time to add a library for one small task and if collections don't contain much items, but it's a good tool to be familiar with.

How to combine 2 Vectors in a JList?

Vector<String> totalProducts = Products.getProductNames();
Vector<String> selectedProducts = Products.getSelectedProductNames();
The selectedProducts vector is a subvector of totalProducts (meaning that selectedProducts contains one, more or all of the elements from totalProducts). What I want is to combine these two vectors and make a single JList, which contains all the elements from totalProducts, and with the elements of selectedProducts already selected.
What I tried:
Vector<Integer> indices = new Vector<Integer>();
JList prdList = new JList(totalProducts);
for(int i = 0; i < totalProducts.size(); i++)
{
for(String name : selectedProducts)
{
if(totalProducts.contains(name)) indices.add(i);
}
}
Object [] objIndices = indices.toArray();
//... Cast from Object [] to int [] ....
prdList.setSelectedIndices(intIndices);
...but this selects all the elements in the final JList.
Previously I tried:
JList prdList = new JList(totalProducts);
for(String tName : totalProducts)
{
for(String sName : selectedProducts)
{
if(totalProducts.contains(sName)) prdList.setSelectedValue(sName, false);
}
}
...but this one selected only the last element from the selectedProducts.
Can you please help me to do it right?
Your attempt that selects all items does so because you're iterating over each item, and if any item from the selectedProducts list is in the total list, adds the iteration item's index to the final selection list. Try changing your loop to something like this:
for(int i = 0; i < totalProducts.size(); i++)
{
String name = totalProducts.get(i);
if(selectedProducts.contains(name)) indices.add(i);
}
in debugging your first attempt (which looks like it should work, what was the contents of your intIndices array? because that looks like it should work, presuming your array conversion works.
however, since selectedproducts is guaranteed to be less items than total, you might want to iterate over that instead?
List<Integer> indices = new ArrayList<Integer>(selectedProducts.size());
for(String name : selectedProducts)
{
int index = totalProducts.indexOf(name);
if (index != -1)
indices.add(index);
}
although, since indexOf is a linear search through a list, it probably doesn't make much of a difference either way.
as for your second attempt, the ListSelectionModel has methods for adding a selected index (addSelectionInterval(int index0, int index1))
, you're using the one that sets (overwrites) the selection.
see http://download.oracle.com/javase/6/docs/api/javax/swing/ListSelectionModel.html
aside: you might want to use List<> instead of Vector<>, as vector has a lot of unecessary synchronization overhead. Unless you need the synchronization....
edit fixed copy+paste of add(i) with add(index)

Categories