Here is my code:
for (int i = 0; i < myarraylist.size(); i++) {
for (int j = 0; j < stopwords.size(); j++) {
if (stopwords.get(j).e
Here is short benchmark that roughly compares various methods to remove elements from array list. Removal by index is really a bad idea since array list shrinks its internal array on every operation. There will be no real difference for small arrays but if you have large chunk of indices to remove it will cost much.
Benchmark Mode Cnt Score Error Units
CollectionsTest.filterToNewListViaLoop avgt 2 4.425 ms/op
CollectionsTest.filterToNewListViaStream avgt 2 5.410 ms/op
CollectionsTest.removeByIndexInReverseOrder avgt 2 69.234 ms/op
CollectionsTest.removeByIterator avgt 2 4.311 ms/op
CollectionsTest.removeViaRemoveAllMethod avgt 2 4.145 ms/op
CODE:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(MILLISECONDS)
@State(Scope.Benchmark)
@Warmup(iterations = 2)
@Measurement(iterations = 2)
public class CollectionsTest {
private static final Random RANDOM = new Random();
private static final int CONTAINER_SIZE = 100_000;
private static final int REMOVE_COUNT = 10_000;
private List<Foo> _container;
private TreeSet<Integer> _indicesToRemove;
private HashSet<Foo> _elementsToRemove;
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(CollectionsTest.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
@Setup(Level.Invocation)
public void setup() {
_container = generateContainerData(CONTAINER_SIZE);
_indicesToRemove = generateIndicesToRemove(REMOVE_COUNT, CONTAINER_SIZE);
_elementsToRemove = new HashSet<>();
_indicesToRemove.stream().map(Foo::new).forEach(_elementsToRemove::add);
}
@Benchmark
public void removeByIndexInReverseOrder() {
int iterations = 0;
for (int arrayIndex : _indicesToRemove.descendingSet()) {
_container.remove(arrayIndex);
}
}
@Benchmark
public void removeByIterator() {
_container.removeIf(foo -> _elementsToRemove.contains(foo));
}
@Benchmark
public void filterToNewListViaStream() {
List<Foo> elementsToKeep = _container.stream()
.filter(foo -> !_indicesToRemove.contains(foo.id))
.collect(Collectors.toList());
}
@Benchmark
public void filterToNewListViaLoop() {
List<Foo> elementsToKeep = new ArrayList<>(CONTAINER_SIZE - REMOVE_COUNT);
for (Foo foo : _container) {
if (!_indicesToRemove.contains(foo.id)) elementsToKeep.add(foo);
}
}
@Benchmark
public void removeViaRemoveAllMethod() {
_container.removeAll(_elementsToRemove);
}
private List<Foo> generateContainerData(int size) {
List<Foo> data = new ArrayList<>();
for (int idx = 0; idx < size; idx++) {
data.add(new Foo(idx));
}
return data;
}
private TreeSet<Integer> generateIndicesToRemove(int count, int containerSize) {
TreeSet<Integer> data = new TreeSet<>();
ThreadLocalRandom.current().ints(0, containerSize)
.distinct()
.limit(count)
.forEach(data::add);
return data;
}
public static class Foo implements Comparable<Foo> {
private static final Comparator<Foo> COMPARATOR = Comparator.comparing(foo -> foo.id);
public int id;
public Foo(int id) {
this.id = id;
}
@Override
public int compareTo(Foo that) {
return COMPARATOR.compare(this, that);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Foo{");
sb.append("id=").append(id);
sb.append('}');
return sb.toString();
}
}
}
while iterating list and you are removing the object use iterator.
Iterator myListItr = myarraylist.iterator();
//Iterate on list
while(myListItr .hasNext()) {
//if stop words is list of string then contains will work as it is. If its your custom object then override equals method.
if(stopwords.contains( myListItr.next())){
myListItr.remove();
}
}