2

I want to iterate over unique pairs in a HashSet, Ideally, I'd be able to make a copy of the iterator and when it has exhausted itself, iterate the iterator I am making copies of, but Iterators do not like being copied, and I suspect that there is a good reason for this, but I do not know what that is.

More specifically, what prevents this (below) behavior from being supported?

Iterator<Object> iter = myhash.iterator();
while(iter.hasNext()){
    object=iter.next();
    Iterator<Object> iterclone = iter.clone();
    while(iterclone.hasNext()){
        setOfObjectPairs.add(object,iterclone.next());
    }
}

Edit: The point of doing this is to save the current state of the iterator, which is already pointing at the i-th element.

Zackkenyon
  • 352
  • 1
  • 2
  • 18

3 Answers3

0

If you cloned an Iterator and the clone modified the underlying Iterable, the original Iterator will throw a ConcurrentModificationException.

You can simply use another iterator for the same set.

Iterator<Object> iter = h.iterator();
        while(iter.hasNext()){
            Object o=iter.next();
            Iterator<Object> iterclone = h.iterator();
            while(iterclone.hasNext()){
                //logic
            }
        }

or you can use and array and iterate over it.

Madhura
  • 551
  • 5
  • 18
  • 1
    this would not be effective, as you would still be double counting. The point is to clone the iterator where it is currently pointing. – Zackkenyon Jan 29 '14 at 06:56
  • In that case you can write your own iterator. OR you can just add your HashSet into an ArrayList and use listIterator(index) – Madhura Jan 29 '14 at 07:01
  • Well, if you describe how to write my own iterator so that this functionality exists so that I don't have to go off researching that, I will accept your answer. – Zackkenyon Jan 29 '14 at 07:17
  • Implementing Iterator is pretty easy... you implement interface iterator and then implementing methods which IDE is complaining about. :) However this is not approriate tool for your purposes. Beside you shouldn't optimize your code before you get REALLY good reason. Before that it's all about readability. – zimi Jan 29 '14 at 08:25
  • Zackkenyon: Refer to this(http://www.dreamincode.net/forums/topic/272393-creating-own-hashset-class-implementing-own-iterator/) link for the same. Its pretty simple. As Zimi said, you just have to implement the interface iterator and implement the methods. And since you want to create the clone, you can implement the clonable interface and override the clone method. But that is the last thing you want to do. I would use the iterating over an array option – Madhura Jan 29 '14 at 08:34
0

If the order to generate the pairs doesn't matter, then you could use the following code, which avoids having to clone the iterator, while still running in O(n*n) time:

HashSet<Integer> set = new HashSet<Integer>();
for (int i = 0; i < 10; i++) {
    set.add(i);
}
int to = 0;
for (int a : set) {
    int index = 0;
    for (int b : set) {
        if (index++ >= to) {
            break;
        }
        System.out.println(a + ", " + b);
    }
    to++;
}
Thomas Mueller
  • 48,905
  • 14
  • 116
  • 132
  • I guess my point is, if you *can* have concurrent iterators, why can't you use cloned iterators? – Zackkenyon Jan 29 '14 at 07:55
  • Well, I guess the authors of the `java.util.` library just thought it's not an important use case to be able to clone an iterator. And I think they are right: If `Iterator` was `Cloneable`, each implementation would have to support that, and there are many implementation of `Iterator`, many of them are user defined. – Thomas Mueller Jan 29 '14 at 08:20
  • Sure, but I can't very well copy the values of the fields in the iterator myself, nor can I construct a new HashKeyIterator from the old iterator, because it is private. – Zackkenyon Jan 29 '14 at 08:39
  • @Zackkenyon My point is: don't try to clone an iterator. Simply accept the fact that there is no (good) way to do it, and use a different approach to solve your problem. Trying to do something with the collection library that it was not designed for will just get you in trouble. I'm not usually a person that easily gives up, but I see no other way here. Instead, I concentrated on the problem you have (the title of your question) and provided a solution for that. You can ask another question "How to clone an Iterator" if you want :-) But please don't change the subject of your question. – Thomas Mueller Jan 29 '14 at 10:10
  • Well, the title of the question is "Iterating over unique pairs in a HashSet (Java)", but now we presented your some solutions for _that_, but you didn't accept any of them or didn't even vote for them, but instead insist that you want to "Clone an Iterator" (because now this is what you want, and you don't seem to be interested any longer about how to iterate over pairs). – Thomas Mueller Jan 30 '14 at 05:18
0

If you will not change iterator (you're only want to save state)

The best way is to do it here is with for each loop I guess

I expect iterators to be only for cases when I modify collection in loop through this collection. For example remove() method from this iterator.

The best way I see it is:

    HashSet<Integer> set = new HashSet<Integer>();
    for (int i = 0; i < 10; i++) {
        set.add(i);
    }
    LinkedList<Integer> arr = new LinkedList<Integer>(set);
    for (Integer i : set) {
        arr.pollFirst();
        for (Integer k : arr) {
            System.out.println(i + " " + k);
        }
    }

Here you're coping you're hashset to LinkedList and you're droping first element from LinkedList every time you're iterating through hashset

Cloning anything in Java is not good practice. See for example Clone() vs Copy constructor- which is recommended in java

Community
  • 1
  • 1
zimi
  • 1,586
  • 12
  • 27