Java: remove a range of indices from a list - java

Consider a linked list of strings I got from somewhere
LinkedList<String> names = getNames();
Now, I want to remove the first k elements from the list. Currently, I'll do it this way:
for (int i = 0 ; i < k ; i++) {
names.removeFirst();
}
Is there some way to do it more efficiently and to instead call something like:
names.removeRange(0, k);
Note that I prefer not to construct a whole new list using sublist(), as for small k values, popping k times would be even more efficient than constructing the new list

Maybe Something like this :
names.subList(0, k).clear();
this is more efficient but doesn't release memory according to sublist it's just a view:
names.sublist(k, names.size());

Related

Iterate through an list of objects and run a function for each - Java

I'm wondering for the simplest method for how to run a specific function for each object in an array (or other list type)
My goal is to be able create a list of objects, and have each object run a specific function as it passes through the iterator.
I've tried a for loop on an arraylist
for (int i = 0; i < testList.size(); i++)
{
this = textList.get(i);
this.exampleFunction();
}
But this gives me a 'Variable expected' error
Assuming you're using Java 8+, and you have a Collection<TypeInList> you could call Collection.stream() and do a forEach on that. Like,
testList.stream().forEach(TypeInList::function);
Your current approach is trying to do things with this that cannot be done. It could be fixed like,
for (int i = 0; i < testList.size(); i++)
{
TypeInList that = testList.get(i); // this is a reserved word.
that.function();
}
or
for (TypeInList x : testList) {
x.function();
}
There are multiple ways to iterate through a list, but the easiest I personally find is like this:
Assuming that your list contains String objects e.g.:
List<String> list = new ArrayList();
list.add("Hello");
list.add("World");
for(String current : list){
System.out.println(current);
}
The loop will iterate twice, and console will output the following:
Hello
World
This approach doesn't rely on indexes (as how you're using it in your question), as such I find it easy to use for iterating through a single list.
However the disadvantage is that if you have 2 separate lists that you would like to iterate through, the lack of indexes makes it a bit more complicated. The easier approach for iterating through multiple lists would be using the traditional approach, something like this:
for(int i=0; i<list.size(); i++){
int x = list1.get(i);
int y = list2.get(i);
}
As such your use-case really determines the ideal method you can adopt.

Optimal way to check for common element among many lists?

I understand that ArrayList<>'s are fastest for searching (O(1) vs. O(n)) and LinkedList<>'s are fastest for inserting & deleting (O(1) vs. O(n)).
My question is, if using a combination of these two, what is the optimal method to check many lists (>2) for common elements?
Current Method
Using three lists and an iterative method:
out:
for(int a = 0; a < list1.size(); a++) {
for(int b = 0; b < list2.size(); b++) {
for(int c = 0; c < list3.size(); c++) {
if(list1.get(a) == list2.get(b) && list1.get(a) == list3.get(c) ) {
System.out.println(list1.get(a)); // list2.get(b) or list3.get(c) could have been subbed
break out;
}
}
}
}
How can this be optimised for efficiency?
EDIT
Thanks for the many helpful responses :)
What I found to work the best was to use the List .retainAll() function.
Again, to find the common elements among three lists, I have refined the method below.
list1.retainAll(list2);
list1.retainAll(list3);
for(int i : list1) {
System.out.println(i);
}
You can get a expected time linear in the number of elements in all lists, assuming the elements implement hashCode:
public static <T> Set<T> commonElements(List<? extends T> list1, List<? extends T>... lists) {
// use LinkedList for efficient delete operation
// make sure elements are distinct to not check the same element multiple times
List<T> commonElements = new LinkedList<>(new HashSet<>(list1));
for (List<? extends T> l : lists) {
// use HashSet for fast contains check
// keep only elements in the list
commonElements.retainAll(new HashSet<>(l));
}
return new HashSet<>(commonElements);
}
This is faster than your approach, since HashSet allows lookup in O(1) expected time.
Note though that for small input lists the preformance can be much worse with this approach.
If you are looking for performance, it would be better to write an API that uses hash look up. list.retainAll(), though is a single clean api call, internally it does lot of processing especially if the argument passed is also a list. Take a look at the implementation of retainAll() of array list here -
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.retainAll%28java.util.Collection%29
You can look at the implementation of the list that you are using and see if that is okay with your performance requirement. If not, you may try something like this...Write an api to return common elements.
private static Set getCommonElements (List dataList, Set dataSet) {
Set commonDataSet = new LinkedHashSet();
if (dataSet == null || dataSet.isEmpty())
return commonDataSet;
for (Object elem: dataList) {
if (dataSet.contains(elem)) {//Hash based look up. Will be faster.
commonDataSet.add(elem);
}
}
return commonDataSet;
}
Then call that repeatedly as below
Set resultSet= new LinkedHashSet(list1);
resultSet= getCommonElements(list2, resultSet);
resultSet= getCommonElements(list3, resultSet);
If you are not concerned about the order, you can just use a hashset instead of linkedhashset.
One problem with this is, this is iterating over the elements in list which will be higher than the common elements. It would be much better if we can iterate over the common elements and look up in the list. But for that, u may have to keep the data in the lists in a hash-baked list/set or maintain a sorted list. Else the lookup will be costly.
You can optimise it using HashMap in java.
Suppose you have n lists with m elements each
Algorithm :
make hashmap h;
loop i=0 to m
loop j=0 to n
increment j[i] key in hashmap h
loop end
loop end
loop i=0 to m for any list
check hashmap value for the element, if equals to n
print element
complexity o(nm),if n <<< m then, complexity(n)
Using the retainAll(List<>) function instead of iterating over each element has significantly reduced run time and improved readability.
New
list1.retainAll(list2);
list1.retainAll(list3);
Old
out:
for(int a = 0; a < list1.size(); a++) {
for(int b = 0; b < list2.size(); b++) {
for(int c = 0; c < list3.size(); c++) {
if(list1.get(a) == list2.get(b) && list1.get(a) == list3.get(c) ) {
System.out.println(list1.get(a));
break out;
}
}
}
}

iterating through list in java using for loop

How does one iterate through a list datastructure using indices. For example consider a sentence in form a list with each element being a word. Can I step through each word using the index? Something like this --
// sentence defined something like this - List<String>
int size = sentence.size();
for (int i=0; i<size-1; i++)
{
System.out.println(sentence[i] + " " + sentence[i+1]);
}
ofcourse the above code doesn't work but is it possible to do something on those lines? As you can see, I want to access the two consecutive elements and using iterators, it starts becoming really messy.
You can use the get(i) method instead of [i]:
for (int i=0; i<size-1; i++) {
System.out.println(sentence.get(i) + " " + sentence.get(i+1));
}
List instances are not the same as arrays. They have specific methods for obtaining items at certain indexes. Try this:
// sentence defined something like this - List<String>
int size = sentence.size();
for (int i=0; i<size-1; i++)
{
System.out.println(sentence.get(i) + " " + sentence.get(i + 1));
}
Now if you had an array (e.g. String[] sentence = new String[]{"hello", "there"}), what you had would work fine.
As a side note, Java has a for-each loop that can be used on both arrays and Lists:
for (String s : sentence) {
// do something
}
Of course, this can't be used in your case because you're accessing elements at multiple indexes in each iteration of your loop - but it's important to know that something like this exists.
The x[i] expression syntax in Java can only be used for arrays. Nothing else.
As other answers have stated, the way to step through the elements of a Java list using indices is to use List.get(int). However, there is an important performance issue that needs to be considered when you do this.
The issue is that the cost of a get(int) call depends on what List implementation class you use:
For an ArrayList (or a Vector) the get(int) operation on a list of length N is O(1). That means that it does not depend on the list length, and in fact it is cheap: only a bit more expensive than an someArray[i].
For a LinkedList, the get(int) operation on a list has to step through the list from the beginning until it reaches the position you asked for. If the list length is N, then the average cost of get(int) (assuming a random position in the list) is O(N); i.e. it is proportional to the list length. If the length is long, then that will be expensive.
By contrast, if you use an Iterator (explicitly, or implicitly by using the for (E e : l) syntax), getting each element will be O(1) for all of the list implementations in java.util and java.util.concurrent (ignoring multi-threading issues such as heavy contention).
Having said that, there are some cases where iterators don't work, and the application needs to use indices.
You can also use Iterator in this case for ex:
first of all put ur elements on arraylist and try to use Iterator like this:
ArrayList arrayList = new ArrayList();
Iterator itr = arrayList.iterator();
while(itr.hasNext())
{
System.out.println(itr.next()); // Print out the elements from arraylist
}
You can process consecutive pairs of values from a list without using indices. Here's one way:
private void processWordsInSentence(List<String> sentence) {
Iterator<String> it = sentence.iterator();
if (it.hasNext()) {
String previous = it.next();
while(it.hasNext()) {
String current = it.next();
// use previous and current values, e.g.
System.out.println(previous + " " + current);
previous = current;
}
}
}
Why would you want to use something like this instead of sentence.get(index)? I would offer a couple of reasons:
In your sample, your processing is really concerned with consecutive
values from the list, not their positions. So there's no "value add"
to having to fiddle with the index explicitly.
Remember that List<T> is an interface with multiple
implementations. ArrayList<T> performs .get(index) in constant
time, but that same call on a LinkedList<T> requires time
proportional to the value of index. So there could be a real performance
consideration.
The processWordsInSentence implementation above does have to deal explicitly with the case of lists with less than two elements. The loop inside the guarding if can be written with a for statement, to separate traversal from processing the actual data a bit more aggressively, if you prefer that style.
private void processWordsInSentence(List<String> sentence) {
Iterator<String> it = sentence.iterator();
if (it.hasNext()) {
for (
String previous = it.next(), current = null;
it.hasNext();
previous = current
) {
// use previous and current values, e.g.
System.out.println(previous + " " + current);
}
}
}
Try this simple code :
List mobileSoftwares = new ArrayList();
mobileSoftwares.add("Android");
mobileSoftwares.add("IOS");
mobileSoftwares.add("Blackberry");
int size = mobileSoftwares.size();
for (int i = 0; i < size - 1; i++)
{
System.out.println(mobileSoftwares.get(i));
}

Remove multiple elements from ArrayList

I have a bunch of indexes and I want to remove elements at these indexes from an ArrayList. I can't do a simple sequence of remove()s because the elements are shifted after each removal. How do I solve this?
To remove elements at indexes:
Collections.sort(indexes, Collections.reverseOrder());
for (int i : indexes)
strs.remove(i);
Or, using the Stream API from Java 8:
indexes.sort(Comparator.reverseOrder());
indexes.stream().mapToInt(i -> i).forEach(l::remove);
Sort the indices in descending order and then remove them one by one. If you do that, there's no way a remove will affect any indices that you later want to remove.
How you sort them will depend on the collection you are using to store the indices. If it's a list, you can do this:
List<Integer> indices;
Collections.sort(indices, new Comparator<Integer>() {
public int compare(Integer a, Integer b) {
//todo: handle null
return b.compareTo(a);
}
}
Edit
#aioobe found the helper that I failed to find. Instead of the above, you can use
Collections.sort(indices, Collections.reverseOrder());
I came here for removing elements in specific range (i.e., all elements between 2 indexes), and found this:
list.subList(indexStart, indexEnd).clear()
You can remove the elements starting from the largest index downwards, or if you have references to the objects you wish to remove, you can use the removeAll method.
you might want to use the subList method with the range of index you would like to remove and
then call clear() on it.
(pay attention that the second parameter is exclusive - for example in this case, I pass 2 meaning only index 0 and 1 will be removed.):
public static void main(String[] args) {
ArrayList<String> animals = new ArrayList<String>();
animals.add("cow");
animals.add("dog");
animals.add("chicken");
animals.add("cat");
animals.subList(0, 2).clear();
for(String s : animals)
System.out.println(s);
}
}
the result will be:
chicken
cat
You can remove the indexes in reverse order. If the indexes are in order like 1,2,3 you can do removeRange(1, 3).
I think nanda was the correct answer.
List<T> toRemove = new LinkedList<T>();
for (T t : masterList) {
if (t.shouldRemove()) {
toRemove.add(t);
}
}
masterList.removeAll(toRemove);
You can sort the indices as many said, or you can use an iterator and call remove()
List<String> list = new ArrayList<String>();
list.add("0");
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
List<Integer> indexes = new ArrayList<Integer>();
indexes.add(2);
indexes.add(5);
indexes.add(3);
int cpt = 0;
Iterator<String> it = list.iterator();
while(it.hasNext()){
it.next();
if(indexes.contains(cpt)){
it.remove();
}
cpt++;
}
it depends what you need, but the sort will be faster in most cases
Use guava! The method you are looking is Iterators.removeAll(Iterator removeFrom, Collection elementsToRemove)
If you have really many elements to remove (and a long list), it may be faster to iterate over the list and add all elements who are not to be removed to a new list, since each remove()-step in a array-list copies all elements after the removed one by one. In this case, if you index list is not already sorted (and you can iterate over it parallel to the main list), you may want to use a HashSet or BitSet or some similar O(1)-access-structure for the contains() check:
/**
* creates a new List containing all elements of {#code original},
* apart from those with an index in {#code indices}.
* Neither the original list nor the indices collection is changed.
* #return a new list containing only the remaining elements.
*/
public <X> List<X> removeElements(List<X> original, Collection<Integer> indices) {
// wrap for faster access.
indices = new HashSet<Integer>(indices);
List<X> output = new ArrayList<X>();
int len = original.size();
for(int i = 0; i < len; i++) {
if(!indices.contains(i)) {
output.add(original.get(i));
}
}
return output;
}
order your list of indexes, like this
if 2,12,9,7,3 order desc to 12,9,7,3,2
and then do this
for(var i = 0; i < indexes.length; i++)
{
source_array.remove(indexes[0]);
}
this should resolve your problem.
If the elements you wish to remove are all grouped together, you can do a subList(start, end).clear() operation.
If the elements you wish to remove are scattered, it may be better to create a new ArrayList, add only the elements you wish to include, and then copy back into the original list.
Edit: I realize now this was not a question of performance but of logic.
If you want to remove positions X to the Size
//a is the ArrayList
a=(ArrayList)a.sublist(0,X-1);
Assuming your indexes array is sorted (eg: 1, 3, 19, 29), you can do this:
for (int i = 0; i < indexes.size(); i++){
originalArray.remove(indexes.get(i) - i);
}
A more efficient method that I guess I have not seen above is creating a new Arraylist and selecting which indices survive by copying them to the new array. And finally reassign the reference.
I ended up here for a similar query and #aioobe's answer helped me figure out the solution.
However, if you are populating the list of indices to delete yourself, might want to consider using this:
indices.add(0, i);
This will eliminate the need for (the costly) reverse-sorting of the list before iterating over it, while removing elements from the main ArrayList.

How do I remove sequential elements from a Java ArrayList?

I'm a relatively new Java programmer and I'm having difficuly removing more than one element from an ArrayList. Ideally I'd like to do something like this:
ArrayList ar1 = new ArrayList();
ar1.add(...)
ar1.add(...)
ar1.add(...)
ar1.add(...)
for (int i = 0; i < 2; i++){
ar1.remove(i);
}
I think iterator might help, but I can't find an example that matches close enough to what I'm trying to do. Any help would be appreciated. Thanks.
Here's what you want to do:
ar1.subList(0, 2).clear();
This creates a sublist view of the first 2 elements of the list and then clears that sublist, removing them from the original list. The subList method exists primarily for this sort of thing... doing operations on a specific range of the list.
You can certainly do that
ArrayList ar1 = new ArrayList();
ar1.add("a");
ar1.add("b");
ar1.add("c");
ar1.add("d");
for (int i = 0; i < 2; i++) {
ar1.remove(i);
}
System.out.println(ar1);
Only pay attention that after you remove first element, other elements shift. Thus, calling
ar1.remove(0);
ar1.remove(1);
will effectively remove first and third elements from the list. This will delete first two elements, though:
ar1.remove(0);
ar1.remove(0);
For indexed removals from a list, you need to count backwards:
for (int i = 1; i >= 0; i--)
otherwise, your first removal shifts the items "above" it in the collection and you don't wind up removing the items you think you are removing.
You can use Collection.removeAll(toRemove) if you have a separate list of objects to remove.
http://download.oracle.com/javase/6/docs/api/java/util/Collection.html
If your collection is indexed based, like ArrayList is, you can call
remove(index)
to remove the element at the index. You can do that in a loop, but beware that removing shifts all the indexes as another answer points out.
If all you want to do is remove the first two elements from the list, then
list.remove(0);
list.remove(0);
should do it.
If you know the indexes of the items you want to remove, you can remove them in reverse order, without worrying about shifting indexes:
ArrayList ar1 = new ArrayList();
ar1.add("a");
ar1.add("b");
ar1.add("c");
ar1.add("d");
int[] indexesToRemove = {0,2,3};
Arrays.sort(indexesToRemove);
for (int i=indexesToRemove.length-1; i>=0; i--) {
ar1.remove(indexesToRemove[i]);
}
You could try this:
List<Whatever> l = new ArrayList<Whatever>();
l.add(someStuff);
Iterator<Whatever> it = l.iterator();
int i = 0;
while (i < 2 && it.hasNext()) {
it.next();
it.remove();
i++;
}
Or, more generally:
List<Whatever> l = new ArrayList<Whatever>();
l.add(someStuff);
Iterator<Whatever> it = l.iterator();
while (it.hasNext()) {
Whatever next = it.next();
if (shouldRemove(next)) {
it.remove();
}
}
EDIT: I guess it depends if you are trying to remove particular indices or particular objects. It also depends on how much logic you need to decide if something should be removed. If you know the indices then remove them in reverse order. If you have a set of Objects to be removed, then use removeAll. If you want to iterate over the list and remove objects that match a predicate then use the above code.

Categories