Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a sublist from an ArrayList efficiently

My Problem


I have a fixed-size ArrayList which contains custom variables. Despite of the ArrayList having a fixed size, sometimes a lot of them will actually be null. The thing is that I need to return the ArrayList without the null variables inside it. One important thing to note: the ArrayList will have all of its non-null items first, and then all of the nulls below them, e.g., the elements are not mixed. Example: [non-null, non-null, .... null, null, null]

My workaround


I though of creating a for-loop that checked (from last to first index) each of the elements inside the ArrayList to determine if it's null or not. If is null, then I'd call this code:

for (i = size-1; i >=0 ; i--) {
    groupList = new ArrayList<>(groupList.subList(0, i));
}

My question


If the ArrayList is too big, this method might me particularly slow (or not?). I was wondering if there exists a better, more performance-friendly solution. AFAIK the .subList method is expensive.

like image 217
Jose Lopez Avatar asked Aug 25 '15 19:08

Jose Lopez


People also ask

What is the way to get subList from an ArrayList?

ArrayList. subList() method. This method takes two parameters i.e. the start index for the sub-list(inclusive) and the end index for the sub-list(exclusive) from the required ArrayList. If the start index and the end index are the same, then an empty sub-list is returned.

How can I split an ArrayList in multiple small ArrayLists?

import org. List<Integer> inputList = new ArrayList(Arrays. asList(100, 101, 102, 103, 104, 105)); /* Change the value of chunkSize to get desired number of elements in each of the partitionedList */ int chunkSize = 5; List<List<Integer>> partitionedList = ListUtils. partition(inputList, chunkSize);

Are ArrayLists inefficient?

Why is ArrayList so much slower? Because an ArrayList has a distinct array object inside of it. Operations typically involve extra indirections (e.g. to fetch the list's size and inner array) and there are extra bounds checks (e.g. checking the list's size and the array's length).


2 Answers

You can have a variant of binary search, where your custom comparator is:

  • Both elements are null/not null? They are equal
  • Only one element is null? The none null is "smaller".

You are looking for the first null element.

This will take O(logn) time, where n is the size of the array.

However, taking the sublist of the ArrayList that is none null (assuming you are going to copy it to a new list object), is going to be linear time of the elements copied, since you must "touch" each of them.

This gives you total time complexity of O(logn + k), where k is number of non null elements, and n is the size of the array.

like image 76
amit Avatar answered Oct 21 '22 15:10

amit


Following all of your outstanding advices, I modified the original method so that I can take the last (first) ever null item position and call the .subList method just once. And here it is:

int lastNullIndex = size - 1;

for (i = lastNullIndex; i >= 0; i--) {
    if (null == groupList.get(i)) {
        lastNullIndex = i;
    } else {
        break;
    }
}

groupList = new ArrayList<>(groupList.subList(0, lastNullIndex));
return groupList;

If you think it can be further modified so as to allow for a better performance, let us know.

like image 28
Jose Lopez Avatar answered Oct 21 '22 15:10

Jose Lopez