views:

291

answers:

6

Hi,

I'm looking for a implementation of java.util.Queue or something in the Google collection who behave like a Queue, but also ensure that each element of the queue is unique. (all further insertion will have no effect)

It's that possible, or will I have to do it by hand?

For now I'm using a Queue, with a LinkedList implementation, and I check the uniqueness before insertion. ( I use a side Map for doing this, add / remove element from the side map before / after the queu ). I don't like it too much.

Any input is welcome. If it's not in the java.util package, then maybe it's a bad idea?

+2  A: 

I'd be tempted to maintain a HashSet containing a key that uniquely identifies the items in the queue side-by-side with it. Then just check the HashSet to see if the item is in the queue before adding it. When you remove an item from the Queue, simply remove the key from the HashSet as well.

tvanfosson
Yes, that what i do at this time. It's working well.
Antoine Claval
+7  A: 

How about a LinkedHashSet? Its iterator preserves insertion order, but because it's a Set, its elements are unique.

As its documentation says,

Note that insertion order is not affected if an element is re-inserted into the set.

In order to efficiently remove elements from the head of this "queue", go through its iterator:

Iterator<?> i = queue.iterator();
...
Object next = i.next();
i.remove();
erickson
The problem is it doesn't implement Queue and hence there's no way to remove elements in FIFO order.
Adamski
@Adamski - removing elements in FIFO order is simple. See my update.
erickson
Easy enough to augment LinkedHashSet to add push and pop. Not efficient, but naive pop could be:Iterator<T> it = iterator();T result = it.next();it.remove();return result;
Brandon DuRette
Nice. Sorry, i miss the LinkedHashSet while scanning the collection. What do you think of implementing java.util.Queue with a home made class, and with a backend LinkedHashSet ?
Antoine Claval
Ah yes ... Of course - Forgot about Iterator.remove().
Adamski
... although creating an iterator for each removal operation seems pretty ugly.
Adamski
It depends on how you want to use the queue. If you are going to add a bunch of objects and then remove a bunch of objects---probably within a single thread---using the `Iterator` is perfectly natural, and I'd probably just reference it as a `Collection`. If you really need a `BlockingQueue` to communicate between threads, this isn't the right approach.
erickson
+4  A: 

This doesn't exist as far as I know but would be fairly simple to implement using a LinkedList in conjunction with a Set:

/**
 * Thread unsafe implementation of UniqueQueue.
 */
public class UniqueQueue<T> implements Queue<T> {
  private final Queue<T> queue = new LinkedList<T>();
  private final Set<T> set = new HashSet<T>();

  public boolean add(T t) {
    // Only add element to queue if the set does not contain the specified element.
    if (set.add(t)) {
      queue.add(t);
    }

    return true; // Must always return true as per API def.
  }

  public T remove() throws NoSuchElementException {
    T ret = queue.remove();
    set.remove(ret);
    return ret;
  }

  // TODO: Implement other Queue methods.
}
Adamski
Although this works, there is a huge performance cosr to it. I dont think you need both a set and a linkedlist
Cshah
that's what tvanfosson is proposing as well, and very close of what i already have. I'm just curious about a more standard way.
Antoine Claval
@Cshah: Why do you think there's a huge cost performance? Assuming your hash algorithm is fast and efficient, set insert and removal operations will approximate to O(1), which is much faster than scanning the LinkedList each time: O(n).
Adamski
@adamki: The approach by tvanfosson is much cleaner. In your case, each element is added to both the queue(linked list) and the set (to ensure uniqueness). I believe that just a hashset should suffice
Cshah
@Cshah: What are you talking about?! tvanfosson's approach is *the same* as mine - He just hasn't provided example code. Also, erickson's approach of using a LinkedHashSet is essentially *the same*, as internally LinkedHashSet contains a linked list. Using "just a hashset" will not provide queue-like behaviour.
Adamski
Why not just use java.util.TreeSet?
Dean J
A TreeSet does not support FIFO access: Elements will be inserted according to their natural ordering (or the ordering of the supplied Comparator) rather thn at the end of the "queue". Granted you could provide a Comparator to mimic FIFO-like behavior but this is an ugly hack IMHO that offers no real benefit.
Adamski
+3  A: 

Checking uniqueness of course has a cost (either in space or time). Seems like it might be interesting to work from something like a PriorityQueue which will maintain a heap sorted by Comparator of the elements. You might be able to leverage that to more efficiently (O(log n)) check existence without maintaining a side map.

If you do want to wrap a Queue with a uniqueness checker, I would strongly recommend using the Google Collections ForwardingQueue to build such a thing.

Alex Miller
+1  A: 

This is a very good question. There is no existing straightforward solution. I'll dig up some code I wrote a while back that attempted to do this, and come back and edit this answer.

EDIT: I'm back. Truly, if you don't need concurrency, you are better off maintaining a Queue and Set separately. For what I was doing, concurrency was a goal, but the best solution I could come up with given that constraint was problematic; basically, since it used a ConcurrentHashMap, the more you were removing the "head" element from the queue (a basic thing to do with a queue), the more unbalanced the hash table would become over time. I can still share this code with you, but I doubt you really want it.

EDIT: For the case where concurrency is required I gave this answer: http://stackoverflow.com/questions/3120495/concurrent-set-queue/3121453#3121453

Kevin Bourrillion
A: 

TreeSet. It's a sorted Set, and Set implies "no duplicate elements".

Dean J
I'm an idiot, and didn't read the requirement "implements Queue". Let me edit this.
Dean J