Java LinkedList - ListIterator cannot add values - java

I have two fields in my custom class List:
LinkedList<String> breadList;
Iterator<String> iterator.
And I've defined two methods:
showBreadList() - for displaying the contents of the list;
addInOrder() - for inserting a new element into the list (the list should be updated in such a way so that elements are maintained in sorted order).
My code:
public class List {
class LinkedListExample {
private LinkedList<String> breadList = new LinkedList<>(); // <-- Edit from the answer: public to private
Iterator<String> iterator;
public void showBreadList() {
iterator = breadList.iterator();
System.out.println("Values in breadList: ");
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
public void addInOrder(String bread) {
ListIterator<String> stringListIterator = breadList.listIterator();
while(stringListIterator.hasNext()) {
if(stringListIterator.next().compareTo(bread) == 0) {
} else if(stringListIterator.next().compareTo(bread) > 0) {
stringListIterator.previous();
stringListIterator.add(bread);
} else if(stringListIterator.next().compareTo(bread) < 0) {
}
}
stringListIterator.add(bread); // <-- Edit: added
}
}
public static void main(String[] args) {
List list = new List();
List.LinkedListExample lle = list.new LinkedListExample();
lle.addInOrder("Ciabatta");
lle.addInOrder("Wheat Bread");
lle.addInOrder("White Bread");
lle.addInOrder("Sourdough");
lle.addInOrder("Flatbread");
lle.showBreadList();
}
}
The list gets populated in the main() method via addInOrder().
Expected output:
Values in breadList:
Ciabatta
Flatbread
Sourdough
Wheat Bread
White Bread
Actual output:
Value in breadList:
I.e. I'm getting nothing. Can anybody give a hint on what I'm doing wrong?

Seems like the goal of your assignment is to learn how to deal with a ListIterator.
The core thing to understand about the Iterators that their cursor always occupies a position in between the elements of the list (and it might also be positioned before the first element and right after the last element). And that's the position where a new element gets inserted when you invoke ListIterator.add().
Here's a quote from the official tutorial Provided by Oracle:
Intuitively speaking, the cursor is always between two elements — the
one that would be returned by a call to previous and the one that
would be returned by a call to next. The n+1 valid index values
correspond to the n+1 gaps between elements, from the gap before the
first element to the gap after the last one. The following figure
shows the five possible cursor positions in a list containing four
elements.
In the method addInOrder() you've messed around with conditions. If fact, only one condition that would check if the next is lexicographically greater than the given string would be enough. If the next is greater we continue iteration, if not we need to move the iterator the previous position by calling previous() and then break from the loop.
Method add() will be invoked on the iterator after the loop, when iterator is the right position to insert a new element.
That's how you can fix your method:
public void addInOrder(String bread) {
ListIterator<String> iterator = breadList.listIterator();
while (iterator.hasNext()) {
String next = iterator.next();
if (next.compareTo(bread) > 0) { // if the next element is lexicographically greater than `bread`, `bread` has to be inserted before it
iterator.previous(); // moving to the position where the new `bread` should be inserted
break; // breaking out from the loop
}
}
iterator.add(bread); // inserting the new kind of bread
}
Example with the sample data from the question:
LinkedListExample lle = new LinkedListExample();
lle.addInOrder("Ciabatta");
lle.addInOrder("Wheat Bread");
lle.addInOrder("White Bread");
lle.addInOrder("Sourdough");
lle.addInOrder("Flatbread");
lle.showBreadList();
Output:
Ciabatta
Flatbread
Sourdough
Wheat Bread
White Bread

Related

Why cant I add to ListIterator while iterating over it?

Im trying to add to a ListIterator while iterating over it but when checking if it worked hasNext() always returns false.
As javadoc states that a ListIterator is "An iterator for lists that allows the programmer to traverse the list in either direction, modify the list during iteration, and obtain the iterator's current position in the list." however when Im trying to add I'm neither getting an Error message nor is the ListIterator getting a new Element.
public void foo() {
List<String> bar = new ArrayList<String>();
bar.add("foobar");
ListIterator<String> quux = bar.listIterator();
while(quux.hasNext()) {
if(quux.next().equals("foobar")) {
quux.add("baz");
}
}
}
At the end of this funtion I expect the ListIterator to contain the new String "baz". However when I call the hasNext() method it returns false. The program even got past the if-Statement it just turns out, that the add-method doesnt do what its supposed to do.
Your code works (after fixed the missed () after new ArrayList<String> and replaced == with the correct method to compare strings, equals:
import java.util.*;
public class test
{
public static void main(String[] args) {
List<String> bar = new ArrayList<String>();
bar.add("foobar");
ListIterator<String> quux = bar.listIterator();
while(quux.hasNext()) {
if(quux.next().equals("foobar")) {
quux.add("baz");
}
}
System.out.println(bar);
}
}
returns:
[foobar, baz]
As you can see, baz were inserted.
It seems that you expect to be able to fetch the added element with next():
nor is the ListIterator getting a new Element
[...]
At the end of this funtion I expect the ListIterator to contain the new String "baz". However when I call the hasNext() method it returns false
However, the JavaDoc for
ListIterator.add() explicitly states that this is not the case:
The new element is inserted before the implicit cursor: a subsequent call to next would be unaffected
If you want to include the element in the iteration you can rewind the list iterator by one position:
if(quux.next().equals("foobar")) {
quux.add("baz");
quux.previous();
}

Remove while iterating leaves element and does not throw Concurrent E

I encountered this piece a of code, that removes item from list while iterating, and yet it does not throw concurrent exception and leaves some items in the list.
Why is that?
Example:.
public class Application {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
for (Integer integer : integerList) {
removeInteger(integerList, integer);
}
System.out.println(integerList.toString()); // prints [2] as it was not removed (while it should be)
}
private static void removeInteger(List<Integer> integerList, Integer integer) {
for (Integer integer1 : integerList) {
if (integer.equals(integer1)) {
int index = integerList.indexOf(integer);
if (index >= 0) {
integerList.remove(index);
}
}
}
}
}
If I change removeInteger method to use Iterator instead and in main I pass a copy of integerList everything works as expected.
First of all if you add some more elements to the list it will still fail with a ConcurrentModificationException.
For the reason that it does not fail with the posted example, we have to take a look at what happens internally.
If you debug you see that in the posted example, both loops are only iterated once. Removing the element in the inner loop (removeInteger method) exhausts both iterators. As there is no further interaction, no error is caused. 'Only' a call of Iterator#next after a modification could cause a ConcurrentModificationException.
Yes, but why does it exhaust them?
Checking the source code of ArrayList#Itr we can see that
public boolean hasNext() {
return cursor != size;
}
only checks a variable called size. This variable size is a property of the ArrayList. When remove is called this variable is decremented. Hence the next time hasNext is called, the Iterator assumes there are no more new elements.
SideNote: cursor points at the next element in the list.

trying to remove the first occurence of the number in the arraylist

public static void main(String [] args){
Scanner input = new Scanner(System.in);
System.out.println("Enter some numbers (all on one line, separated by spaces):");
String line = input.nextLine();
String[] numbers = line.split(" +");
ArrayList<Integer> a = new ArrayList<Integer>();
for(int i=0; i<numbers.length; i++)
a.add(new Integer(numbers[i]));
System.out.println("The numbers are stored in an ArrayList");
System.out.println("The ArrayList is "+a);
System.out.print("\nEnter a number: ");
int p = input.nextInt();
System.out.println(removeNumber(a,p));
System.out.println(removeNumber2(a,p));
}
public static <T> ArrayList<T> removeNumber(ArrayList<T> a, Integer e)
{
ArrayList<T> b = new ArrayList<T>();
for(int i = 0; i< a.size();i++)
{
if (a.get(i).equals(e))
a.remove(e);
}
return a;
}
if ex.value = 4, I want to remove 4 from the arrayList. If my arraylist contains [5,12,4,16,4], I want to remove the first occurence of four from it, and save it to another arraylist.
Don't want to use Iterators
Without using an iterator, here's what you could do to fix your code :
for(int i = 0; i< a.size();i++) {
if (a.get(i).equals(e.value)) {
a.remove(e.value);
i--;
}
}
Beyond the change of == to equals, you have to decrement i whenever you remove an element from the ArrayList. The reason for that is that removing the ith element from an ArrayList decreases the indices of all the elements that follow it by one. Therefore, the i+1th element will become the new ith element, so you must decrement i in order not to skip the next element.
EDIT : For some reason I was sure you wanted to remove all occurences of the number from the list, and not just the first one. If you only want to remove one element from the list, you don't have to worry about iterating over the rest of the list after removing that element.
You cannot iterate over an ArrayList and modify it at the same time, without an Iterator
Do like this :
for(Iterator<T> i = a.iterator(); i.hasNext();)
{
if (i.next().equals(e.value))
{
i.remove();
}
}
BTW, your b ArrayList is useless.
Along with the suggestion of using iterators, you should not be using the operator == which checks for reference equality. This will always be false in your scenario. You want to use the equals method instead which checks for value equality.
if (a.get(i).equals((Integer)e.value)))
You don't need to iterate through the list, either with an iterator or an index. ArrayList has a remove method that searches for and removes an element, and returns true or false depending on whether it found an element to remove. So you can say
while (true) {
boolean found = a.remove(e.value);
if (!found) {
break;
}
}
or
boolean found;
do {
found = a.remove(e.value);
} while(found);
or if you value compactness over readability,
do { } while(a.remove(e.value));
Note that a.remove(e), as you have in your original code, won't work at all. The ArrayList is an ArrayList of Integer, but e is an EX6. Thus, a.remove(e) won't find e in the list at all, since it isn't even the correct type. It should compile fine, since remove is defined to allow any Object as a parameter, but it will never find anything (since the equals method of Integer always returns false for a non-Integer).

How to get nth element of a Set

More specifically: how to get the nth element of a LinkedHashSet (which has a predictable iteration order)? I want to retrieve the nth element inserted into this Set (which wasn't already present).
Is it better to use a List:
List<T> list = new ArrayList<T>(mySet);
T value = list.get(x); // x < mySet.size()
or the toArray(T [] a) method:
T [] array = mySet.toArray(new T[mySet.size()]);
T value = array[y]; // y < mySet.size()
Other than the (likely slight) performance differences, anything to watch out for? Any clear winner?
Edit 1
NB: It doesn't matter why I want the last-inserted element, all that matters is that I want it. LinkedHashSet was specifically chosen because it "defines the iteration ordering, which is the order in which elements were inserted into the set (insertion-order). Note that insertion order is not affected if an element is re-inserted into the set."
Edit 2
This question seems to have devolved into a discussion of whether any Set implementation can ever preserve original insertion order. So I put up some simple test code at http://pastebin.com/KZJ3ETx9 to show that yes, LinkedHashSet does indeed preserve insertion order (the same as its iteration order) as its Javadoc claims.
Edit 3
Modified the description of the problem so that everybody isn't too focused on retrieving the last element of the Set (I originally thought that the title of the question would be enough of a hint — obviously I was wrong).
This method is based on the updated requirement to return the nth element, rather than just the last element. If the source is e.g. a Set with identifier mySet, the last element can be selected by nthElement(mySet, mySet.size()-1).
If n is small compared to the size of the Set, this method may be faster than e.g. converting to an ArrayList.
/**
* Return an element selected by position in iteration order.
* #param data The source from which an element is to be selected
* #param n The index of the required element. If it is not in the
* range of elements of the iterable, the method returns null.
* #return The selected element.
*/
public static final <T> T nthElement(Iterable<T> data, int n){
int index = 0;
for(T element : data){
if(index == n){
return element;
}
index++;
}
return null;
}
I'd use the iterator of the LinkedHashSet if you want to retrieve the last element:
Iterator<T> it = linkedHashSet.iterator();
T value = null;
while (it.hasNext()) {
value = it.next();
}
After the loop execution value will be referring to the last element.
So I decided to go with a slight variation of the answer by #Juvanis.
To get at the nth element in a LinkedHashSet:
Iterator<T> itr = mySet.iterator();
int nth = y;
T value = null;
for(int i = 0; itr.hasNext(); i++) {
value = itr.next();
if (i == nth) {
break;
}
}
Version 2 of the code:
public class SetUtil {
#Nullable
public static <T> T nthElement(Set<T> set, int n) {
if (null != set && n >= 0 && n < set.size()) {
int count = 0;
for (T element : set) {
if (n == count)
return element;
count++;
}
}
return null;
}
}
NB: with some slight modifications the method above can be used for all Iterables<T>.
This avoids the overhead of ensuring that a Set and a List stay in sync, and also avoids having to create a new List every time (which will be more time-consuming than any amount of algorithmic complexity).
Obviously I am using a Set to ensure uniqueness and I'd rather avoid a lengthy explanation as to why I need indexed access.
You can go with below solution,
here i have added object of ModelClass in HashSet.
ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
m1 = (ModelClass) itr.next();
if(nth == index) {
System.out.println(m1);
break;
}
}
Set is unordered so the information on the last element inserted is lost. You cannot as such get the last element inserted. So don't use Set in the first place, or, if you really want to keep track of the last element, create a class containing that like this
class mySetAndLast extends Set{
T last;
Set<T> mySet;
}
now the question is what is the 'last element inserted'. Imagine your set was empty
-> insert x -> ok, x is the last inserted
-> insert y (y!=x) -> ok: y is the last inserted
-> insert x -> ?
is now x or y the last inserted?
x does not get inserted because y was the last element inserted and x already is an element of the set, on the other hand x from the user's point of view was the last inserted..
For your own, internal purpose, you could "hack" your own Set from any List implementation:
public class ListSet<E> extends ArrayList<E> implements Set<E> {
#Override
public boolean add(E item) {
return contains(item) ? false : super.add(item);
}
// ... and same for add(int, E), addAll(...), etc.
}
That example is slow (O(n) for an add) but, as you are the one implementing it, you can go back to it with smarter code for contains() based on your specifications.

Moving stack elements back to a Single linked list

I'm trying to move list elements to the stack and back to the list again, reversing their order.
I'm having trouble with the last bit of transferring the stack back into the list.
I've been using the stack.pop(); in different ways but nothing seems to work.
I'm able to just print out the output of stack.pop so far, but I really want to be able to transfer the stack contents back into the list.
public class ReverseArray {
public static void main(String[] args) throws EmptyStackException {
// TODO Auto-generated method stub
MyLinkedList<GameEntry>myList = new MyLinkedList<>();
//populate the list
myList.addFirst(new Node<GameEntry>(new GameEntry("Marche", 313), null));
myList.addFirst(new Node<GameEntry>(new GameEntry("Apricot", 754), null));
myList.addFirst(new Node<GameEntry>(new GameEntry("Dragon", 284), null));
myList.addFirst(new Node<GameEntry>(new GameEntry("Erasure", 653), null));
//print the list
System.out.println(myList);
System.out.println();
System.out.println("New Reversed List:");
//reverse the list elements
reverse(myList);
}
public static <V> void reverse ( MyLinkedList<V> list) throws EmptyStackException{
//code to reverse goes here
NodeStack<GameEntry> stack = new NodeStack<GameEntry>();
Node<GameEntry> scores = list.getHead();
for ( int i = 0; i < list.getSize(); i++){
stack.push(scores.getElement());
scores = scores.getNext();
}
while(!stack.isEmpty()){
System.out.print(stack.pop() + " ");
}
}// end reverse
}//end main
You should keep order from the stack, so add them at the end of a new LinkedList:
while(!stack.isEmpty()){
GameEntry entry = stack.pop();
list.addLast(entry);
}
Assuming you want the list to only contain the reversed elements you have to clear the list at first. Depending on your implementation you have a clear() method or must call remove() several times until the list is empy.
Afterwards you can add code like this:
while(!stack.isEmpty()){
GameEntry entry = stack.pop();
list.addFirst(entry);
}
That way you should have the reversed order of your elements in the list.
An alternativ would be implementing the List Interface with your MyLinkedList and use the Collections.reverse().
Totally missed that the order would be the same as on the input list. Therefore you have two options:
Use a Queue instead of a Stack.
Use second Stack that gets filled with the contents of your first Stack. This may look like:
NodeStack<GameEntry> secondStack = new NodeStack<GameEntry>();
while(!stack.isEmpty()){
secondStack.push(stack.pop());
}
while(!secondStack.isEmpty()){
GameEntry entry = secondStack.pop();
list.addFirst(entry);
}

Categories

Resources