I have to make a custom iterator that iterators through an array endlessly. I have no clue how to do this considering I've never worked with iterators in java before. If anyone could help me out at all and explain to me, I'd appreciate it very much.
public class Numbers{
private int[] array;
public Numbers(int[] array){
this.array = array
}
public static void main(String[] args) {
Numbers n = new Numbers();
Iterator num = n.sequence();
for(int i = 0; i < 10; i++){
if (num.hasNext()){
System.out.print(num.next() + " ");
System.out.println();
}
}
}
}
See below:
public class Numbers implements Iterable<Integer> {
private int[] array;
private int i;
public Numbers(int[] array) {
this.array = array;
i = 0;
}
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
#Override
public boolean hasNext() { return true; }
#Override
public Integer next() {
int j = i;
i = (i + 1) % array.length;
return array[j];
}
#Override
public void remove() {}
};
}
}
You could then do:
Numbers n = new Numbers(new int[]{1,2,3});
for (int i : n)
System.out.println(i); // or anything else
This would result in the infinite loop:
1
2
3
1
2
3
1
2
...
Relevant javadocs:
- Iterator
- Iterable
Another way to do it is just to have an infinite while-loop as such:
int[] array = new int[]{1, 2, 3};
int i = 0;
while (true) {
System.out.println(array[i]); // or anything else
i = (i + 1) % array.length;
}
This is basically how an iterator works. This example uses a List, but you can use an iterator against any collection that implements java.lang.Iterable.
List<String> someList; // assume this has been instantiated and has values in it
ListIterator<String> it = someList.listIterator();
while (it.hasNext()) {
String value = it.next();
// do something with value
}
Pretty much, you instantiate the iterator by telling the collection to give you a reference to its iterator. Then you loop by calling hasNext(), which will keep you going until you have no more elements. The call to next() pulls the next item from the iterator and increments its position by one. A call to remove() will remove from the list the last item returned by next() (or previous().)
Note, of course, that I've been using java.util.ListIterator instead of java.util.Iterator because the ListIterator is a special implementation of Iterator optimized for use against lists, like in the example I gave above.
You cannot use an iterator against an array. You'd need to use a vanilla for-loop or convert it into a List or another object that implements Iterable.
To loop through the above list endlessly, your loop would look something like this:
while(it.hasNext()) {
String value = it.next();
// do processing
if (!it.hasNext()) {
it = someList.listIterator(); // reset the iterator
}
}
To loop through the array using a for-loop endlessly:
for (int i = 0; i < myArray.length; i++) {
myArray[i];
// do something
if (i == myArray.length - 1) {
i = 0; // reset the index
}
}
Alteratively you could have your Numbers class implement Iterable directly.
Work with iterators is basically always the same.
First get the iterator from your array:
Iterator iterator = yourArray.iterator();
Second iterate while it has items:
while(iterator.hasNext()) {
Object element = iterator.next();
}
Related
We are trying to compile our program, but we keep getting a NoSuchElementException. Anyone that has a clue on why this keeps occurring? Thanks in advance. In the following I will attach both the code where we implement the exception and also the main method.
EDIT - whole code in the following:
import java.util.Iterator;
import edu.princeton.cs.algs4.*;
public class RandomQueue<Item> implements Iterable<Item> {
private Item[] queue;
private int N;
private int size;
// Your code goes here.
public RandomQueue() { // create an empty random queue
N = 0;
size = 2;
queue = (Item[]) new Object[size];
}
public boolean isEmpty() {// is it empty?
if(N == 0) {
return true;
} else {
return false;
}
}
public int size() {// return the number of elements
return size;
}
public void resizeArray() {
if(3/4*size < N) {
size = size*2;
Item[] queueUpdated = (Item[]) new Object[size];
for(int i = 0; i < queue.length; ++i) {
queueUpdated[i] = queue[i];
}
queue = queueUpdated;
} else if (N < 1/4*size) {
size = size/2;
Item[] queueUpdated = (Item[]) new Object[size];
for(int i = 0; i < size-1; ++i) {
queueUpdated[i] = queue[i];
}
queue = queueUpdated;
}
}
public void enqueue(Item item) {// add an item
if(N < queue.length) {
queue[N++] = item;
resizeArray();
}
}
public Item sample(){ // return (but do not remove) a random item
if(isEmpty()) {
throw new RuntimeException("No such elements");
} else {
return queue[StdRandom.uniform(N)];
}
}
public Item dequeue(){ // remove and return a random item
if(isEmpty()) {
throw new RuntimeException("Queue is empty");
} else {
System.out.println(N);
int indexFraArray = StdRandom.uniform(N);
Item i = queue[indexFraArray];
queue[N] = null;
queue[indexFraArray] = queue[N--];
resizeArray();
return i;
}
}
private class RandomQueueIterator<E> implements Iterator<E> {
int i = 0;
public boolean hasNext() {
return i < N;
}
public E next() {
if (!hasNext()) {
throw new java.util.NoSuchElementException(); // line 88
}
i++;
return (E) dequeue();
}
public void remove() {
throw new java.lang.UnsupportedOperationException();
}
}
public Iterator<Item> iterator() { // return an iterator over the items in
random order
return new RandomQueueIterator();
}
// The main method below tests your implementation. Do not change it.
public static void main(String args[]) {
// Build a queue containing the Integers 1,2,...,6:
RandomQueue<Integer> Q = new RandomQueue<Integer>();
for (int i = 1; i < 7; ++i) Q.enqueue(i); // autoboxing! cool!
// Print 30 die rolls to standard output
StdOut.print("Some die rolls: ");
for (int i = 1; i < 30; ++i) StdOut.print(Q.sample() +" ");
StdOut.println();
// Let's be more serious: do they really behave like die rolls?
int[] rolls= new int [10000];
for (int i = 0; i < 10000; ++i)
rolls[i] = Q.sample(); // autounboxing! Also cool!
StdOut.printf("Mean (should be around 3.5): %5.4f\n", StdStats.mean(rolls));
StdOut.printf("Standard deviation (should be around 1.7): %5.4f\n",
StdStats.stddev(rolls));
// Now remove 3 random values
StdOut.printf("Removing %d %d %d\n", Q.dequeue(), Q.dequeue(), Q.dequeue());
// Add 7,8,9
for (int i = 7; i < 10; ++i) Q.enqueue(i);
// Empty the queue in random order
while (!Q.isEmpty()) StdOut.print(Q.dequeue() +" ");
StdOut.println();
// Let's look at the iterator. First, we make a queue of colours:
RandomQueue<String> C= new RandomQueue<String>();
C.enqueue("red"); C.enqueue("blue"); C.enqueue("green");
C.enqueue("yellow");
Iterator<String> I = C.iterator();
Iterator<String> J = C.iterator();
StdOut.print("Two colours from first shuffle: "+I.next()+" "+I.next()+" ");
StdOut.print("\nEntire second shuffle: ");
while (J.hasNext()) StdOut.print(J.next()+" ");
StdOut.println("\nRemaining two colours from first shuffle: "+I.next()+" "+I.next()); // line 142
}
}
I compile in cmd and this is the error I get
the error happens here:
enter image description here
and here:
enter image description here
Your iterator is modifying your collection. This is non-standard at least and seems to confuse yourself.
You are creating two iterators over your queue C, which has 4 elements in it at this time:
Iterator<String> I = C.iterator();
Iterator<String> J = C.iterator();
You ask the former iterator for two elements:
StdOut.print("Two colours from first shuffle: "+I.next()+" "+I.next()+" ");
This removes (dequeues) those two elements through this line:
return (E) dequeue();
Now your queue has 2 elements in it. N is 2.
Your try to remove the remaining 2 elements here:
StdOut.print("\nEntire second shuffle: ");
while (J.hasNext()) StdOut.print(J.next()+" ");
However, after one element has been removed, J.i is 1 and N is 1, so the iterator J considers the queue exhausted and only gives you this one element. There’s one left. N is 1. Yet you try to remove another two elements:
StdOut.println("\nRemaining two colours from first shuffle: "+I.next()+" "+I.next()); // line 142
This is bound to fail. Fortunately it does. next calls hasNext, which in turn compares:
return i < N;
I.i is 2 (since we had previously taken 2 elements from I) and N is 1, so hasNext returns false, which causes next to throw the exception.
The solution is simple and maybe not so simple: Your iterator should not remove any elements from your queue, only return the elements in order.
And the real answer: You should learn to use a debugger. It will be a good investment for you.
I encountered this error while using the haseNext() method for ArrayLists:
error: cannot find symbol
while(isduplicate == false && birthdays.hasNext())
this is my code:
import java.util.*;
class hello
{
public static void main(String args[])
{
Integer size = 4;
Integer count = 5;
Integer doubleinarray = 0;
for(Integer i = 0 ; i < count ; i++) {
List<Integer> birthdays = new ArrayList<Integer>();
birthdays = CreateSimulator(size);
Integer countdown = size;
boolean isduplicate = false;
while(isduplicate == false && birthdays.hasNext()) {
Integer date = birthdays.get(0);
birthdays.remove(0);
if(birthdays.contains(date)) {
isduplicate = true;
doubleinarray ++;
}
}
}
System.out.println(doubleinarray / count * 100);
}
public static List<Integer> CreateSimulator(int size)
{
List<Integer> Birthdays = new ArrayList<Integer>(size);
Random rand = new Random();
for(Integer i =0 ; i < size ; i++) {
Birthdays.add(rand.nextInt(364) + 1);
}
return Birthdays;
}
}
I didn't understand why it doesn't accept the hasNext. besides this, the rest of the code works fine.
appreciate your help
thanks :)
you have to do something like:
Iterator<Integer> birthdaysIterator = birthdays.iterator();
And with the birthDaysIterator you can call hasNext.
But this is not recommended nowadays.
You are better of performing a normal for, like:
with normal for:
for (int i = 0; i < birthdays.size(); i++) {
System.out.println(birthdays.get(i));
}
with for-each loop:
for (Integer birthday : birthdays) {
System.out.println(birthday);
}
with Java 8 streams:
birthdays.forEach((birthday) -> {
System.out.println(birthday);
});
EDIT:
Per #OHGODSPIDERS, if you use the other 3 versions that I suggested, you will run into ConcurrentModificationException. In order to avoid that, you can either stick with your iterator, or you can use an intermediate list to keep the elements which you want to delete, and remove them all afterwards.
Example:
List<String> toRemove = new ArrayList<>();
for (String birthday : birthdays) {
if (someCondition) {
toRemove.add(birthday);
}
}
birthdays.removeAll(toRemove);
birthdays is of type List which does not have a method of that name. What you are looking for is the iterator, which you can access like this:
Iterator<Integer> iterator = birthdays.iterator()
And use it to traverse the list. hasNext is a method of the type Iterator.
As mentioned, the List class does not have a hasNext() method
An alternate way to use this, would be to check if it is not empty
while (isduplicate == false && !birthdays.isEmpty()) {
public class MyArrayList<T> implements MyList<T>{
int num; //number of things in the list
T[] vals; //to store the contents
#SuppressWarnings("unchecked")
public MyArrayList() {
num = 0;
vals = (T[]) new Object[3];
}
public T getUnique(){
T distinct = null;
int count = 0;
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){
count++;
}
if (count == 1){
return distinct;
}
}
}
if (distinct == null){
throw new IllegalArgumentException();
}
return distinct;
}
I am trying to work on a get Unique Method. A method getUnique that takes no arguments and returns the first value in the list that appears only once. (For example, calling the method on the list [1,2,3,1,2,4] would return 3 since 1 and
2 both appear more than once.) If the list is empty or all its values appear more than once, the method throws a NoSuchElementException
I have added some FIXME's to your code:
public T getUnique(){
T distinct = null;
int count = 0; // FIXME: move this initialization inside the i loop
for (int i=0; i<vals.length; i++){
distinct = vals[i];
for (int j = 0; j<vals.length; j++){
if (vals[j] == vals[i]){ // FIXME: use .equals() not ==
count++;
}
if (count == 1){ // FIXME: move this check outside the j loop
return distinct;
}
}
}
if (distinct == null){ //FIXME: no check needed, just throw it
throw new IllegalArgumentException();
}
return distinct; //FIXME: no valid return can reach this point
}
Patrick Parker's advice will fix your code, but I wanted to provide a cleaner and faster solution to the problem of finding a unique element in a list. This algorithm runs in time O(n) instead of O(n^2).
public static <T> Optional<T> getUnique(List<T> ls) {
// Create a map whose keys are elements of the list and whose values are
// lists of their occurences. E.g. [1,2,3,1,2,4] becomes {1->[1, 1],
// 2->[2, 2], 3->[3], 4->[4]}. Then elements.get(x).size() tells us how
// many times x occured in ls.
Map<T, List<T>> elements = ls.stream()
.collect(Collectors.groupingBy(x -> x));
// Find the first element that occurs exactly one time in ls.
return ls.stream().filter(x -> elements.get(x).size() == 1)
.findFirst();
}
You might call it like this:
Integer[] vals = {1,2,3,1,2,4};
System.out.println(getUnique(Arrays.asList(vals))
.orElseThrow(NoSuchElementException::new));
This code uses Java 8 streams and Optional. Below is another implementation of the same algorithm that doesn't use Java 8 language features; if you've never encountered streams, you may find it more understandable.
private static <T> T getUnique(List<T> arr) {
Map<T, Integer> numOccurrences = new HashMap<>();
for (T item : arr) {
numOccurrences.put(item, 1 + numOccurrences.getOrDefault(item, 0));
}
for (T item : arr) {
if (numOccurrences.get(item) == 1) {
return item;
}
}
throw new NoSuchElementException();
}
So I have this code:
public class SortedIntList extends IntList
{
private int[] newlist;
public SortedIntList(int size)
{
super(size);
newlist = new int[size];
}
public void add(int value)
{
for(int i = 0; i < list.length; i++)
{
int count = 0,
current = list[i];
if(current < value)
{
newlist[count] = current;
count++;
}
else
{
newlist[count] = value;
count++;
}
}
}
}
Yet, when I run the test, nothing prints out. I have the system.out.print in another class in the same source.
Where am I going wrong?
EDIT: Print code from comment:
public class ListTest
{
public static void main(String[] args)
{
SortedIntList myList = new SortedIntList(10);
myList.add(100);
myList.add(50);
myList.add(200);
myList.add(25);
System.out.println(myList);
}
}
EDIT2: Superclass from comment below
public class IntList
{
protected int[] list;
protected int numElements = 0;
public IntList(int size)
{
list = new int[size];
}
public void add(int value)
{
if (numElements == list.length)
System.out.println("Can't add, list is full");
else {
list[numElements] = value; numElements++;
}
}
public String toString()
{
String returnString = "";
for (int i=0; i<numElements; i++)
returnString += i + ": " + list[i] + "\n";
return returnString;
}
}
Let's walk through the logic of how you want it to work here:
first you make a new sorted list passing 10 to the constructor, which make an integer array of size 10.
now you call your add method passing 100 into it. the method sets position 0 to 100
now you add 50, the method sets 50 in position 0 and 100 in position 1
now you add 200, which gets placed at position 2
and you add 25. which gets set to position 0, and everything else gets shuffled on down
then your method will print out everything in this list.
So here are your problems:
For the first add, you compare current, which is initialized at 0, to 50. 0 will always be less than 50, so 50 never gets set into the array. This is true for all elements.
EDIT: Seeing the super class this is how you should look to fix your code:
public class SortedIntList extends IntList
{
private int[] newlist;
private int listSize;
public SortedIntList(int size)
{
super(size);
// I removed the newList bit becuase the superclass has a list we are using
listSize = 0; // this keeps track of the number of elements in the list
}
public void add(int value)
{
int placeholder;
if (listSize == 0)
{
list[0] = value; // sets first element eqal to the value
listSize++; // incriments the size, since we added a value
return; // breaks out of the method
}
for(int i = 0; i < listSize; i++)
{
if (list[i] > value) // checks if the current place is greater than value
{
placeholder = list[i]; // these three lines swap the value with the value in the array, and then sets up a comparison to continue
list[i] = value;
value = placeholder;
}
}
list[i] = value; // we are done checking the existing array, so the remaining value gets added to the end
listSize++; // we added an element so this needs to increase;
}
public String toString()
{
String returnString = "";
for (int i=0; i<listSize; i++)
returnString += i + ": " + list[i] + "\n";
return returnString;
}
}
Now that I see the superclass, the reason why it never prints anything is clear. numElements is always zero. You never increment it because you never call the superclass version of the add method.
This means that the loop in the toString method is not iterated at all, and toString always just returns empty string.
Note
This is superseded by my later answer. I have left it here, rather than deleting it, in case the information in it is useful to you.
Two problems.
(1) You define list in the superclass, and presumably that's what you print out; but you add elements to newList, which is a different field.
(2) You only add as many elements to your new list as there are in your old list. So you'll always have one element too few. In particular, when you first try to add an element, your list has zero elements both before and after the add.
You should probably have just a single list, not two of them. Also, you should break that for loop into two separate loops - one loop to add the elements before the value that you're inserting, and a second loop to add the elements after it.
I have to iterate through an arraylist in this manner.
ArrayList<Integer> li = new ArrayList<Integer>();
li.add(20);
li.add(30);
li.add(40);
li.add(50);
li.add(70);
for (int i = 0; i < li.size() - 1; i++)
System.out.println(li.get(i) + " " + li.get(i + 1));
Output:
20 30
30 40
40 50
50 70
How to do the same using an iterator?
Use two iterators. I tested this and it worked for me.
Iterator<Integer> first = li.listIterator();
// Will raise IndexOutOfBoundsException if list is empty.
Iterator<Integer> second = li.listIterator(1);
while (second.hasNext()) {
System.out.println(first.next() + " " + second.next());
}
Edit: No need for inner if. Silly me.
Explanation: the listIterator(index) method returns an iterator that starts at the specified position in the list where as listIterator() returns an iterator that starts at position zero.
The first iterator therefore starts at 0 and the second starts at 1. Then it is merely a question of printing the next() on both. This will work irrespective of whether the number of elements in the list is odd or even.
Edit 2
My logic fu is very weak today. Thanks #barjak for pointing out the case about the empty list and the unnecessary first.hasNext().
It's a bit more complicated:
Iterator<Integer> iter = li.iterator();
if (iter.hasNext()) {
for (int y = iter.next(), x; iter.hasNext(); y = x) {
x = iter.next();
System.out.println(y + " " + x);
}
}
or:
if (iter.hasNext()) {
for (int x = iter.next(); iter.hasNext();) {
System.out.println(x + " " + (x = iter.next()));
}
}
Slightly Modified Sagar V's solution to make it work. One iterator is enough to achieve this.
Iterator iter = li.iterator();
Integer int1 = null;
while (iter.hasNext()) {
if (int1 == null) {
int1 = (Integer) iter.next();
}
System.out.print(int1 + " ");
if (iter.hasNext()) {
Integer int2 = (Integer) iter.next();
System.out.println(int2);
int1 = int2;
} else {
break;
}
}
}
There are many solutions, that can be appropriate depending on your needs.
Solution 1 : fixed-size view
The classical way to iterate on a subset of a list is to create a narrower view of the original list, and to iterate on this whole view. The subList method is used to create such a view.
List<Integer> l = // initialization code
int limitIndex = Math.max(l.size()-1, 0); // needed for empty list
for (int v : l.subList(0, limitIndex)) {
// your code
}
Note that I used a 'foreach' loop, which is a convenient way to use iterators. This is strictly equivalent to this code :
Iterator<Integer> it = l.subList(0, limitIndex).iterator();
while(it.hasNext()) {
int v = it.next();
// your code
}
Also, note that the subList method does not create a new list : it only creates a 'view' on the original list. The content of the original list is not copied, and all changes made to the original list are visible from the list created by subList.
Solution 2 : a custom Iterator/Iterable
If all you need is an iterator that always iterates from 0 to n-1, you can define a new Iterable tailored to that particular need.
public class NoLastIterable<T> implements Iterable<T> {
private final List<T> backend;
public NoLastIterable(List<T> backend) {
this.backend = backend;
}
public Iterator<T> iterator() {
return new Iterator<T>() {
private int nextIndex;
public boolean hasNext() {
return nextIndex < backend.size() -1;
}
public T next() {
return backend.get(nextIndex++);
}
public void remove() {
throw new UnsupportedOperationException("not implemented");
}
};
}
}
This class is used like this :
for (int v : new NoLastIterable<Integer>(l)) {
// your code
}
Solution 3
You can even create your custom view of a List, just like subList does, but with more flexibility.
public class NoLastList<T> extends AbstractList<T> {
private final List<T> backend;
public NoLastList(List<T> backend) {
this.backend = backend;
}
#Override
public T get(int index) {
if (index >= size()) {
throw new IndexOutOfBoundsException();
}
return backend.get(index);
}
#Override
public int size() {
return Math.max(0, backend.size()-1);
}
}
Same usage as the other solutions :
for (int v : new NoLastList<Integer>(l)) {
// your code
}
The benefits of this solution can be seen in the following situation :
the original list is created and initialized
the NoLastList instance is created (as a view of the original List)
some elements are added to the original list
In this situation, iterating over NoLastList will take into account the elements that were added lately. NoLastList always represents a view of the elements from 0 to n-1, even if n (the size) changes.