Reputation: 205
Here is my code:
for (int i = 0; i < myarraylist.size(); i++) {
for (int j = 0; j < stopwords.size(); j++) {
if (stopwords.get(j).equals(myarraylist.get(i))) {
myarraylist.remove(i);
id.remove(i);
i--; // to look at the same index again!
}
}
}
I have problem.. after element removed, all index always changed, the loop above so messy.
To illustrate: I have 54 data, but loop above become messy after element removed.. so only 50 data that checked.
Is there another way or fix my code to remove multiple element by index?? element index is so important to me, to remove another arraylist that have the same index.
Upvotes: 14
Views: 37200
Reputation: 1
Assume you have the input as an ArrayList
and a list of indices to be deleted. If the input ArrayList
list does not contain nulls, then you can do it this way:
List<?> newList = new ArrayList<>(oldList);
for (int i : indicesToRemove) {
newList.set(i, null);
}
newList.removeIf(Objects::isNull);
This way does not require sorting the indexes to be removed and takes advantage of the fact that ArrayList
has its own optimal removeIf
implementation.
Upvotes: 0
Reputation: 714
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();
}
}
}
Upvotes: 1
Reputation: 419
Ok this is very good problem to solve. Lets start with an exmaple
We have data = [5,2,7,3,9,34,63,23,85,23,94,7]
indexes to remove
int index[] = [5,2,7,9]
Note : As you remove single item from array other elements get shifted by 1.
If we use ArrayList to remove elements of indexes then first you need to sort the indexes in descending.
i.e indexes = [9,7,5,2] then remove the element from index
ArrayList<Integer> data = Arrays.asList(new Integer[] {5,2,7,3,9,34,63,23,85,23,94,7});
for(int i=0;i<index.length;i++){
data.remove(index[i]);
}
Upvotes: 2
Reputation: 9578
Using ListIterator
ArrayList<String> list = new ArrayList<String>();
// List : ["java", ".net", "javascript", "html", "css", "selenium", "image", "Spring"]
ArrayList<Integer> indexes = new ArrayList<Integer>();
// indexes : [5, 3, 2, 5, 0]
// Sort the Indexes in Order to remove from back words. and make Unique
TreeSet<Integer> uniqueSorted = new TreeSet<Integer>();
uniqueSorted.addAll(indexes);
// To remove all elements from the ArrayList and make its size = 0
indexes.clear();
indexes.addAll(uniqueSorted);
// Iterate form back, so that if size decreases also no problem.
ListIterator<Integer> li = indexes.listIterator(indexes.size());
// we can traverse a List in both the directions (forward and Backward).
while(li.hasPrevious()) {
int position = li.previous();
list.remove(position);
}
Upvotes: 0
Reputation: 1443
One thing you need to keep in mind is that when you use ArrayLists
that they are meant to be versatile, moreso than Arrays
. You can shorten an array by removing an entire index, add an index to it, and do wonderfulness with ArrayLists
.
This is a common problem with people who do not realize, or remember, that when you remove a value, the ArrayList
indexes (or whatever the correct plural is) readjust and the ArrayList
shortens.
When attempting to remove elements from an ArrayList
, you should always start at the end of the ArrayList
.
for(int x = arrayList.size() - 1; x > 0; x--)
{
arrayList.remove(x);
}
This should provide you with the function that you are looking for. Take a look at the ArrayList API for other methods that may help you.
Upvotes: 29
Reputation: 63104
Use Iterator.remove()
to remove elements while iterating.
for (Iterator<String> iter = myarraylist.iterator(); iter.hasNext(); ) {
String element = iter.next();
if (element meets some criteria) {
iter.remove();
}
}
Or use Google Guava's filter which returns a filtered view and leaves the original list unchanged.
Iterable<String> filtered = Iterables.filter(myarraylist, new Predicate<String>() {
public boolean apply(String element) {
return true of false based on criteria
}
});
Upvotes: 14
Reputation: 3339
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();
}
}
Upvotes: 0
Reputation: 3898
looks like as you want to remove one collection from another.. You should use java.util.Collection#removeAll method instead
Upvotes: 1
Reputation: 13558
Not sure about why you want to do this by index, but you can try this (untested):
int dynamicSize = myarraylist.size();
for (int i = 0; i < dynamicSize; i++) {
for (int j = 0; j < stopwords.size(); j++) {
if (stopwords.get(j).equals(myarraylist.get(i))) {
myarraylist.remove(i);
id.remove(i);
i--; // to look at the same index again!
dynamicSize--;
}
}
}
Upvotes: 0