remove specific object does not work in Java ArrayList - java

I have an ArrayList of object containing a reference to their parent object.
I am trying to remove every objects within a specific parent (so equals to the parent object).
If I do:
System.out.println(parent);
my console output:
ParentObject#1f8166e5
if I do:
for(int i = 0; i < array.size(); i++){
if(array.get(i).getParent().equals(parent)){
array.remove(i);
}
}
And (test)
for(int i = 0; i < array.size(); i++){
if(array.get(i).getParent().equals(parent)){
System.out.println(parent + ":" + array.get(i).getParent());
}
}
My console output something like:
ParentObject#1f8166e5:ParentObject#1f8166e5
What's wrong with the snippet above?
Why array.remove(i) did not work?

I suspect the problem is that after you've removed element i (which moves everything after it up the list - the element at index n + 1 now has index n etc) you're then skipping the next element. So if you have two consecutive elements to remove, you're missing the second one. The simplest fix is to work from the end:
for (int i = array.size() - 1; i >= 0; i--) {
if (array.get(i).getParent().equals(parent)) {
array.remove(i);
}
}
EDIT: As noted in another answer, it's generally better to use an iterator for removal anyway. In your case, this would look like this:
// We don't know what the Foo type is...
for (Iterator<Foo> iterator = array.iterator(); iterator.hasNext(); ) {
Foo element = iterator.next();
if (element.getParent().equals(parent)) {
iterator.remove(); // Note: *not* array.remove(...)
}
}

You can't remove objects while iterating. You should use Iterator if you want to remove element while iterating

Related

Can i iterate over specific Elements in a list in Java?

Given a list of Elements. For example list1 = {a,b,c,d,e}
I want to return an iterator that only iterates over the elements that satisfy a certain condition.
If for example b,d,e meet that condition, then the return value is an iterator that iterates only over those elements b,d,e.
Not allowed to use builtin java collections.
Also I have built my own linked list and iterator.
I have tried doing this by creating a list and adding only the elements where the condition is met.
Then returning an iterator over that new list.
The problem is, that later on i want to remove elements with this iterator and those removed elements should also be removed in the original list.
Is this somehow possible?
I am aware that this does not work:
public Iterator<Y> iterator(X x) {
MyLinkedList<Y> temp = new MyLinkedList<>();
for (int i = 0; i < listY.size(); i++) {
if(!x.satisfies(listY.get(i))){
temp.addFirst(listY.get(i));
listY.remove(i);
}
}
MyIterator<Y> iter1 = new MyIterator<>(listY);
for (int i = 0; i < temp.size(); i++) {
listY.addFirst(temp.get(i));
}
return iter1;
}

Finding an element with the Java For each loop

I want to loop through a LinkedList using For each and access the element after the one I am at right now. If I would use an Array and the usual for(int i = 0; i < ... ; i++), I would be looking for the element i+1. Is there a possibility of reaching the element after the one I am at right now?
Is there a possibility of reaching the element after the one I am at right now?
If you use a simple "for each" loop, then No. The "current position" within the list is encoded to the list's Iterator. When you use "for each", the Iterator is hidden from your application.
Instead you need to do something like this:
List<Element> list = ...
Element current = null;
Element next = null;
Iterator<Element> it = list.iterator();
while (it.hasNext()) {
current = next;
next = it.next();
if (current == null) {
continue;
}
// process 'current' and use `next` when you need to refer to
// the following on element.
}
if (next != null) {
// process 'next' as the last element.
}
Notes:
If null is a valid list element, then use a flag instead.
Using two iterators for the same list might give you a neater solution.
You could also do something similar to this using a for each ... and keeping track of the "previous" element in a variable, like I do above. See #Jezor's answer.
It is inadvisable to use get(i) on a (large) LinkedList because get(int) is an O(N) operation for a LinkedList in the general case.
You can neither determine the index of next element in enhanced for loop nor it's value.
You can keep the reference to previous element though:
// List is initialized somewhere in the code.
List<Element> elements = ...;
Element previousElement = null;
for (Element element: elements) {
if (previousElement != null) {
// ... your code here...
// previousElement is elements[i]
// element is elements[i + 1]
}
previousElement = element;
}
In the above example you can instantiate previousElement with a null object to avoid the null check.
What you really want to use is good, old for loop with a counter:
List<Element> elements = ...;
for (int i = 0; i < elements.size(); ++i) {
// elements.get(i) is elements[i]
// elements.get(i + 1) is elements[i + 1]
// But be careful, (i + 1) will be out of bounds for the last element!
}
Don't make your life unnecessarily complicated.
If you're using the auto-iterator for-each style loop such as:
for (T elem: myList) {
// ...
}
then there isn't an immediate way to access the "next" element while you're looking at the current one without saving a reference to the element you last saw. It is also possible with using indexOf, but this approach gets very messy when duplicates are found in the list. Regardless, I think your problem would be better addressed using indexing over the list instead.
If you're iterating over your LinkedList object using indexed-based access (as opposed to an iterator or for-each, for example,) you can do:
for (int i = 0; i < myList.size(); i++) {
// ...
if ((i + 1) < myList.size()) {
T nextElem = myList.get(i+1); // fetch the element at the next index
// then do whatever you want with "nextElem"
}
// ...
}
where T refers to the type of LinkedList you are using, i.e. String if your list definition was something like LinkedList<String> myList = new LinkedList<>();.

Java how to remove element from List efficiently

Ok, this is a proof-of-concept I have on my head that has been bugging me for a few days:
Let's say I have:
List<String> a = new ArrayList<String>();
a.add("foo");
a.add("buzz");
a.add("bazz");
a.add("bar");
for (int i = 0; i < a.size(); i++)
{
String str = a.get(i);
if (!str.equals("foo") || !str.equals("bar")) a.remove(str);
}
this would end up with the list ["foo", "bazz", "bar"] because it would read the string at index 1 ("buzz"), delete it, the string at index 2 ("bazz") would jump to index 1 and it would be bypassed without being verified.
What I came up with was:
List<String> a = new ArrayList<String>();
a.add("foo");
a.add("buzz");
a.add("bazz");
a.add("bar");
for (int i = 0; i < a.size(); i++)
{
String str = a.get(i);
boolean removed = false;
if (!str.equals("foo") || !str.equals("bar"))
{
a.remove(str);
removed = true;
}
if (removed) i--;
}
It should work this way (atleast it does in my head lol), but messing with for iterators is not really good practice.
Other way I thought would be creating a "removal list" and add items to that list that needed to be removed from list a, but that would be just plain resource waste.
So, what is the best practice to remove items from a list efficiently?
Use an Iterator instead and use Iterator#remove method:
for (Iterator<String> it = a.iterator(); it.hasNext(); ) {
String str = it.next();
if (!str.equals("foo") || !str.equals("bar")) {
it.remove();
}
}
From your question:
messing with for iterators is not really good practice
In fact, if you code oriented to interfaces and use List instead of ArrayList directly, using get method could become into navigating through all the collection to get the desired element (for example, if you have a List backed by a single linked list). So, the best practice here would be using iterators instead of using get.
what is the best practice to remove items from a list efficiently?
Not only for Lists, but for any Collection that supports Iterable, and assuming you don't have an index or some sort of key (like in a Map) to directly access to an element, the best way to remove an element would be using Iterator#remove.
You have three main choices:
Use an Iterator, since it has that handy remove method on it. :-)
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (/*...you want to remove `it.next()`...*/) {
it.remove();
}
}
Loop backward through the list, so that if you remove something, it doesn't matter for the next iteration. This also has the advantage of only calling list.size() once.
for (int index = list.size() - 1; index >= 0; --index) {
// ...check and optionally remove here...
}
Use a while loop instead, and only increment the index variable if you don't remove the item.
int index = 0;
while (index < list.size()) {
if (/*...you want to remove the item...*/) {
list.removeAt(index);
} else {
// Not removing, move to the next
++index;
}
}
Remember that unless you know you're dealing with an ArrayList, the cost of List#get(int) may be high (it may be a traversal). But if you know you're dealing with ArrayList (or similar), then...
Your first example will likely cause off-by-one errors, since once you remove an object your list's indexes will change. If you want to be quick about it, use an iterator or List's own .remove() function:
Iterator<String> itr = yourList.iterator();
while (itr.hasNext()) {
if ("foo".equals(itr.next()) {
itr.remove();
}
}
Or:
yourList.remove("foo");
yourList.removeAll("foo"); // removes all
ArrayList.retainAll has a "smart" implementation that does the right thing to be linear time. You can just use list.retainAll(Arrays.asList("foo", "bar")) and you'll get the fast implementation in that one line.

java array nullpointer

I'm trying to find minimum of an array. The array contain Nodes - a node contains of an element E and a priority int. Im want to find the Node in the array with the smallest priority.
#Override
public E min() {
Node temp = S[0];
for(int i = 1; i<S.length; i++){
int prio= S[i].getPrioritet(); <-- nullpointer excp.
if(prio<temp.getPrioritet()){
temp = S[i];
}
}
return temp.getElement();
But i get an nullpointer exception when i try to use it. Does anybody know what im doing wrong?
Here is my test:
PrioritetArraySorteret<String> p = new PrioritetArraySorteret<String>();
p.insert(1, "Hello");
p.insert(3, "Hi");
p.insert(4, "Hawdy");
System.out.println(p.min());
}
start with i=0 as the array is indexed
for(int i = 0; i<S.length; i++){
int prio= S[i].getPrioritet(); <-- nullpointer excp.
if(prio<temp.getPrioritet()){
temp = S[i];
}
}
It simply means that the element at one of the indexes of array S is null. Maybe you're initialized the array at a size n but filled in less than n positions.
Altering like this will probably fix it:
for(int i = 1; i<S.length; i++){
if(S[i] != null) {
int prio= S[i].getPrioritet(); <-- nullpointer excp.
if(prio<temp.getPrioritet()){
temp = S[i];
}
}
}
That said, you might be reinventing the wheel here a bit. Using a simple ArrayList parameterized with some type that you define which encapsulates a value and priority would do. You could then have that type implement Comparable with a compareTo method that uses the priority, or write a Comparator to use for finding the minimum:
List<YourType<String>> list = new ArrayList<YourType<String>>();
Collections.min(list);
Or, if you're using a custom Comparator:
Collections.min(list, yourComparator);
-- edited for min instead of sort. Sorry.
The array S has not been initialized or one/more elements has been initialized.

How would I remove just one instance of a parameter in an array in java?

I have the code below and I need to see whether or not there are duplicates and if there are, then remove only one instance of it. If there is only one instance, it is still removed. I know I have to use a counter somehow and resize the array but I'm not really sure how.
Listable[]newitems = new Listable[items.length-1];
for(int i = 0;i<items.length;i++){
if(items[i]!=itemToRemove){
break;
}
else{
for(int j = i;j<items.length-1;++j){
newitems[j] = items[j+1];
}
}
items = newitems;
}
You need to loop through the array until you find an instance of the element to remove, then allocate a new array (since it needs to be shorter) and copy everything except the item to be removed from the original to the new array. Your code is stopping after the first item that is not the one you want to remove. Try this instead:
Listable[] newitems = items; // default in case itemToRemove isn't found
for (int i = 0; i<items.length; i++) {
if (items[i] == itemToRemove) {
newitems = new Listable[items.length - 1];
System.arraycopy(items, 0, newitems, 0, i);
System.arraycopy(items, i+1, newitems, i, items.length - i - 1);
break;
}
}
items = newitems;
It might be better to use items[i].equals(itemToRemove) instead of ==, depending on the requirements.
Use a LinkedHashSet. A Set is a collection that does not contain duplicate elements. A LinkedHashSet allows you to maintain the array order. If ordering is not important just use a HashSet.
Set<Listable> set = new LinkedHashSet<Listable>();
for(Listable l : items) {
set.add(l);
}
Listable[] newitems = set.toArray(new Listable[set.size()]);
This saves copying arrays multiple times but relies on the equals and hashCode methods of Listable working correctly to be able to distinguish unique elements.
I think the break is throwing things off since it'll immediately terminate the loop. Is continue what you're wanting instead? At first glance, most of the rest of the code looks like it would work. But what happens when you set items = newItems in the for loop?.
If I read your description right, you just want to keep items when they are in the list 2 or more times.
// count the instances
LinkedHashMap<Listable,Integer> map = new LinkedHashMap<Listable, Integer>();
for(int i = 0; i < items.length; i++) {
int count = 1;
if (null != map.get(items[i])) {
count += map.get(items[i]);
}
map.put(items[i], count);
}
// add it to the new list if the count is more than 1
ArrayList newList = new ArrayList<Listable>();
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
if (((Integer)pairs.getValue()) > 1) {
newList.add(pairs.getKey());
}
}
return newList.toArray();

Categories

Resources