how to remove list element - java

I am trying to remove list element but get this exception
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(AbstractList.java:161)
at apollo.exercises.ch08_collections.Ex4_RemoveOdd.removeOdd(Ex4_RemoveOdd.java:25)
at apollo.exercises.ch08_collections.Ex4_RemoveOdd.main(Ex4_RemoveOdd.java:15)
here is my code
public class Ex4_RemoveOdd {
removeOdd(Arrays.asList(1,2,3,5,8,13,21));
removeOdd(Arrays.asList(7,34,2,3,4,62,3));
public static void removeOdd(List<Integer> x){
for(int i=0;i<=x.size()-1;i++){
if (x.get(i)%2==0){
System.out.println(x.get(i));
}else{
x.remove(i);
}
}
}
}
So I make new class just to try to remove the element
public static void main(String[] args) {
List<Integer> x = Arrays.asList(1,2,3,5,8,13,21);
x.remove(1);
}
but still have error
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(AbstractList.java:161)
at apollo.exercises.ch08_collections.Ex4_RemoveOdd.main(Ex4_RemoveOdd.java:14)
FYI:I try to solve this excercise https://github.com/thecodepath/intro_java_exercises/blob/master/src/apollo/exercises/ch08_collections/Ex4_RemoveOdd.java

Arrays.asList returns a fixed-size list. Any call that will try to modify its size (by adding or removing elements) will throw this exception.
Use the ArrayList constructor that takes a collection as parameter instead.
removeOdd(new ArrayList<>(Arrays.asList(1,2,3,5,8,13,21)));
Also as noted in comments, it's safer (and highly recommended) to use the List's iterator to remove the elements from it.
Currently with your for-loop approach you will skip elements that you want to remove. For example when calling the method with the list [1,2,3,5,8,13,21], the first iteration will remove 1 so all the elements will be shifted by one in the list. Then the value of i is 1, the size of the list is 6 and list.get(1) will return 3 not 2 and so on.
At the end you will get [2, 5, 8, 21], which is not what you want.
If you are using java-8, your code could be simplified as
public static void removeOdd(List<Integer> x){
x.removeIf(i -> i%2 != 0);
}

Related

Shuffling ObservableList fires incorrect change notification

Method FXCollections.shuffle() fires only wasRemoved change notification. As we may know, shuffling isn't only about removing, but removing and adding.
In the documentation we can see:
Shuffles all elements in the observable list. Fires only one change notification on the list.
If I'm not mistaken, a single change can contain both wasAdded and wasRemoved. What a shame wasPermutated isn't being fired with the default ObservableList FX api (or is it?).
Code to test it out:
public class SimpleMain {
public static void main(String[] args) {
ObservableList<Integer> integers = FXCollections.observableArrayList(1, 2, 3, 4);
integers.addListener(initListener());
FXCollections.shuffle(integers);
}
private static ListChangeListener<Integer> initListener() {
return change -> {
while (change.next()) {
if (change.wasPermutated()) {
System.out.println("wasPermutated");
} else if (change.wasRemoved()) {
System.out.println("wasRemoved");
} else if (change.wasAdded()) {
System.out.println("wasAdded");
}
}
};
}
}
Problem
Your code assumes that wasAdded() and wasRemoved() are mutually exclusive, whether you intended that or not. That assumption is wrong. If one or more contiguous elements are replaced then both those methods will return true.
Keep in mind there's a difference between a Change object and a "change". A single Change instance can carry multiple changes. When the documentation says:
Fires only one change notification on the list.
It is not saying only one Change object will be sent to the ListChangeListener. What it's saying is that the Change object will only carry one change. In other words, the Change#next() method will only return true for the first invocation and thus your while loop will only loop once.
Solution
You need to rewrite your code with the knowledge that both wasAdded() and wasRemoved() can both be true. For instance, here's a listener that checks for all types of changes:
private static ListChangeListener<Integer> initListener() {
return change -> {
while (change.next()) {
if (change.wasPermutated()) {
System.out.println("wasPermutated");
} else if (change.wasUpdated()) {
System.out.println("wasUpdated");
} else if (change.wasReplaced()) {
System.out.println("wasReplaced");
} else if (change.wasRemoved()) {
System.out.println("wasRemoved");
} else { // only other change type is "added"
System.out.println("wasAdded");
}
}
};
}
The above uses wasReplaced() which is the same as wasAdded() && wasRemoved(). Note that a check for wasReplaced() must happen before either wasRemoved() or wasAdded() if you use an if-else-if structure. Otherwise the above will suffer the same problem your code has.
If you insert the above into your code and run it you'll see the following output:
wasReplaced
The documentation of ListChangeListener.Change gives a more general explanation (and example) of how to implement a ListChangeListener.
Note the example in the documentation does not check for wasReplaced() specifically. Instead, it processes both removed and added elements in a final else block (after wasPermutated() and wasUpdated() return false). This is possible because getRemoved() and getAddedSubList() will return empty lists if no element was removed or added, respectively. And it's typically the same effect if you process any removed elements and then any added elements as it is if you specially handle replacements. Depending on your use case, however, it may be beneficial to specially handle replacements.
Why not Permutation?
The way they've implemented the shuffle method is:
public static void shuffle(ObservableList list, Random rnd) {
Object newContent[] = list.toArray();
for (int i = list.size(); i > 1; i--) {
swap(newContent, i - 1, rnd.nextInt(i));
}
list.setAll(newContent);
}
Source: javafx.collections.FXCollections, JavaFX 15.
As you can see, the elements are extracted out into an array, the array is shuffled, and then the elements in the list are replaced with the array. That results in a single "replacement change" being fired.
I added one line to your ListChangeListener in the while loop:
System.out.println("change: "+change);
The output I get is:
change: { [1, 2, 3, 4] replaced by [4, 2, 3, 1] at 0 }
wasRemoved
That hints at your mistake. The verb used in the string representation is "replaced".
Getting rid of the 'else's in your listener and adding a check for wasReplaced() you will see that is exactly what you get.

Stack that you can move nth element to the top of the stack

I'm looking for a Stack data structure that also allows moving the nth element to the top of the stack. So in addition to pop(), push(), peek() I want something like moveToTop(int n) where the top of the stack n=0 and the bottom of the stack n=size-1.
What would be the best way to implement that? I'm working in Java.
there is no the moveToTop methed in standard stack data structure ,but if you want to do,i think you can implement like follows:
public class MyStack<T> extends Stack<T>{
public synchronized void moveToTop(int n) throws Exception {
int size = this.size();
if(n>size) {
throw new Exception("error position");
}
T ele = remove(n);
push(ele);
}
}
Why reinvent? Simple is Stack class
https://docs.oracle.com/javase/8/docs/api/java/util/Stack.html
It inherits remove(int index) from Vector.
You can create another array or other underlying structure to hold items temporarily. Move the items in front of item n into that, push that items back and push the item you want to top of that.
public class MyStack<T> {
T items[size];
....
void moveToTop(int n)
{
T obj = items[n];
T[] tempItems = new T[n - 1];
Arrays.copyOf(items, n - 1);
System.arraycopy(items, 0, tempItems, 0, n - 1);
System.arraycopy(tempItems, 0, items, 1, n - 1);
items[0] = obj;
}
....
}
Removed other parts for brevity.
Instead of doing all this hassle, you can check Double-Linked list or Skip List.
java.util.LinkedList fulfills your requirement, because it's linked list / stack / queue at the same time.
Relevant methods:
public E remove(int index)
Remove by index, and get the removed value.
public void push(E e)
Push to top.
So, what you need to do is:
Figure out the index.
Remove it by index, and get the return value.
Push the return value to top.
There are couple ways to implement stack that I know:
- Implement it using extension of Vector
- Implement it using any List component
- Implement it as a Linked Data Structure
- Implement it using underlying Java Array
I suggest you to implement it with using underlying Java Array. It's hard to implement comparing to others but it will be really helpful to understand the logic.

Using synchronizedList with for loop and adding items inside it

I'm using
Collections.synchronizedList(new ArrayList<T>())
part of the code is:
list = Collections.synchronizedList(new ArrayList<T>());
public void add(T arg) {
int i;
synchronized (list) {
for (i = 0; i < list.size(); i++) {
T arg2 = list.get(i);
if (arg2.compareTo(arg) < 0) {
list.add(i, arg);
break;
}
}
Is it right that for loop is actually using iterator and therefore I must wrap the for with synchronized?
Is it thread-safe to use synchronized and make addition inside it like I did here?
I'm sorry if these questions are very basic, I'm new to the subject and didn't find answers on the internet.
Thank you!!
Is it right that for loop is actually using iterator and therefore I must wrap the for with synchronized?
There are two parts to your question.
Firstly, no, you're not using an iterator here, this is a basic for loop.
The enhanced for loop is the for loop which uses an iterator:
for (T element : list) { ... }
You can see in the language spec how this uses the iterator - search for where it says "The enhanced for statement is equivalent to a basic for statement of the form".
Secondly, even though you're not using an iterator, you do need synchronized. The two are orthogonal.
You are doing multiple operations (the size, the get and the add), with dependencies between them. You need to make sure that no other thread interferes with your logic:
the get depends on the size, since you don't want to try to get an element with index >= size, for instance;
the add depends on the get, since you're apparently trying to ensure the list elements are ordered. If another thread could sneak in and change the element after you get it, you might insert the new element in the wrong place.
You correctly avoid this potential interference this through synchronization over list, and creating the synchronizedList in such a way that nothing other than the synchronizedList can get direct access to the underlying list.
If your arg2.compareTo(arg) never return 0 (zero) you can use TreeSet. Will be much more simple:
set = Collections.synchronizedSet(new TreeSet<T>());
public void add(T arg) {
set.add(arg);
}
If you need hold same items (compareTo returns 0) then use the list:
list = new ArrayList<T>();
public void add(T arg) {
synchronized (list) {
int index = Collections.binarySearch(list, arg);
list.add(index, arg);
}
}
First and second cases complexity will be log(N) (10 for 1000 items). Your code complexity is N (1000 for 1000 items).

arraylist remove eliminates following objects

I'm getting a very strange action in my code. I have an ArrayList of the following class.
class mySocket
{
public String name;
public Socket sck;
public mySocket(String n,Socket s)
{
this.name=n;
this.sck=s;
}
}
I declare the object like this
ArrayList<mySocket> handler = new ArrayList<>();
Now the problem is that when I try to remove an item using this method:
public void removeByName(String name)
{
synchronized(this)
{
mySocket t;
int i;
for(i=0;i<handler.size();i++)
{
t=handler.get(i);
if((t.name.equals(name)))
{
handler.remove(i);
break;
}
}
}
}
The remove function clears everything that follows the index.
For Example:
if this ArrayList has 3 elements and I call handler.remove(1) it removes not only 1 but also the object on line 2.
I think your issue is that you are using an indexed for loop and removing by index. In your example, if your list has 3 elements and you remove index 1, the object that was at index 2 is still there. It's just now at index 1.
A better way to do what you're attempting is to use an iterator or for-each loop.
//code outside for loop the same
for( mySocket socket : handler ) {
if((socket.name.equals(name)))
{
handler.remove(socket);
break;
}
}
Is the ordering of your mySocket objects important? If not, storing them in a Map keyed by name would save you some trouble. Then you would just call handler.remove(name). This operation is safe, even if name doesn't exist in the map. Also, for current uses of the collection handler that don't care aobut the name, you can retrieve the unordered Set of mySockets by calling map.values(). You would then be able to iterate over that Set using an iterator or for-each as above.
You CAN NOT remove items in a Collection while looping through them, the result, as you have seen, is undefined.
You either have to build a list of items to be removed and use
originalList.removeAll(itemsToBeRemoved);
Or you build your loop using an iterator.
Iterator<mySocket> handlerIterator = handler.iterator();
while (handlerIterator.hasNext()) {
mySocket t = handlerIterator.next();
if (t.name.equals(name)) {
handlerIterator.remove();
}
}

ArrayList remove error

I'm working on a project for school but i'm a little stuck right now
My problem is that i have an arrayList of Squares
Each Square has a value(from 0 to 100). Its starting value is 9999 so i can check if its is checked.
If a square is checked i want it to be removed from the arrayList.
So after a while there will be no Squares left.
there is a little bit of code where the first value is set so thats why i check if the value is 9999.
But i get an error. One that i havent seen before.
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
Vak = Square
this is my code:
while (!vakken.isEmpty()) { // check if empty
Iterator itrVak = vakken.iterator();
while (itrVak.hasNext()) {
Vak vak = (Vak) itrVak.next(); // here is get the error
if (vak.getValue() != 9999) {// check if square value is 9999
Collection checkVakken = vak.getNeighbour().values();
Iterator itre = checkVakken.iterator();
while (itre.hasNext()) {
Vak nextVak = (Vak) itre.next();
if (nextVak != null) {
if (nextVak.getValue() == 9999) {
nextVak.setValue(vak.getValue() + 1); // set value by its neighbour
vakken.remove(vak);
checkvakken.add(vak);
}
}
}
} else {
vakken.remove(vak);
checkvakken.add(vak);
}
}
}
You are removing elements from the collection while you are iterating it. As the iterator may produce unpredictable results in this situation, it fails fast throwing the exception you encountered.
You may only alter a collection through the iterator's methods while traversing it. There should be remove method on the iterator itself, that removes the current element and keeps the iterator intact.
While iterating, you should use Iterator instance for removing object:
itre.remove();
You can try like this:
itre.remove();
ITERATOR never lets you modify when you are iterating.. you need to use loops instead.. this happens coz you are using the Iterator, same time other thread is modifying the list...

Categories

Resources