一个确保元素唯一性的队列?

Ant*_*val 61 java queue collections unique-constraint guava

我正在寻找java.util.Queue的实现或Google集合中表现得像Queue的东西,但也要确保队列中的每个元素都是唯一的.(所有进一步插入都没有效果)

这是可能的,还是我必须手工完成?

现在我正在使用一个带有LinkedList实现的Queue,并在插入之前检查唯一性.(我使用侧面Map来执行此操作,在队列之前/之后添加/删除侧面图中的元素).我不太喜欢它.

欢迎任何输入.如果它不在java.util包中,那么也许这是一个坏主意?

eri*_*son 48

怎么样LinkedHashSet?它的迭代器保留了插入顺序,但因为它是a Set,它的元素是唯一的.

正如其文件所述,

请注意,如果将元素重新插入到集合中,则不会影响插入顺序.

为了有效地从这个"队列"的头部删除元素,请通过它的迭代器:

Iterator<?> i = queue.iterator();
...
Object next = i.next();
i.remove();
Run Code Online (Sandbox Code Playgroud)

  • 问题是它没有实现Queue,因此无法以FIFO顺序删除元素. (5认同)
  • 它还取决于您是否要在处理元素时添加到队列的末尾.从队列中删除元素的处理过程中添加到队列是定义良好的行为,但有一个迭代器,你会得到一个ConcurrentModificationException的,因为内置的Java集合假设它是一个线程问题,不会有人滥用收集和迭代器好像这两个组合是一个Queue实现. (5认同)
  • @Adamski-按FIFO顺序删除元素很简单。查看我的更新。 (2认同)
  • ...虽然为每个删除操作创建一个迭代器似乎非常难看. (2认同)

Ada*_*ski 22

据我所知,这不存在,但使用LinkedList与以下内容相结合实现起来相当简单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.
}
Run Code Online (Sandbox Code Playgroud)

  • @Cshah:你在说什么?!tvanfosson的方法与我的方法相同*他只是没有提供示例代码.此外,erickson使用LinkedHashSet的方法基本上*相同*,因为内部LinkedHashSet包含链表.使用"只是一个哈希集"不会提供类似队列的行为. (3认同)
  • 关于`add`中的`return true`."Collection#add"和"Queue #add"的合同之间是否存在冲突?这个集合应该保证唯一性,所以它应该根据`Collection` javadoc返回`false`.同时,`Queue` javadoc明确地提到该方法为返回`true`或抛出异常.http://docs.oracle.com/javase/7/docs/api/java/util/Queue.html#add(E)http://docs.oracle.com/javase/7/docs/api/java/ util/Collection.html #add(E)在这种情况下,不确定应该遵循这两个合同中的哪一个. (2认同)
  • 目的是实现队列处理的唯一性,queue#add 肯定应该返回 set#add 的返回值,因为在调用该方法时您可能想知道该元素是否已经在其中。此外,此类应实现其余的 Queue 方法,如 element()、offer()、poll()、peek()。除此之外,这个类绝对满足需求 (2认同)

tva*_*son 6

我很想维护一个包含一个键的HashSet,该键与它并排唯一地标识队列中的项目。然后只需检查 HashSet 以查看该项目是否在队列中,然后再添加它。当您从队列中删除一个项目时,只需从 HashSet 中删除该键即可。


Ere*_*evi 5

只是为了完成亚当斯基的回答:

/**
 * A queue that keeps each element only once. 
 * If you try to add an element that already exists - nothing will happen.
 * 
 * @author Adamski http://stackoverflow.com/a/2319156/827927
 * @NotThreadSafe
 */
public class UniqueQueue<T> implements Queue<T> {

private final Queue<T> queue = new LinkedList<T>();
private final Set<T> set = new HashSet<T>();

@Override 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.
}

@Override public boolean addAll(Collection<? extends T> arg0) {
    boolean ret = false;
    for (T t: arg0)
        if (set.add(t)) {
            queue.add(t);
            ret = true;
        }
    return ret;
}

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

@Override public boolean remove(Object arg0) {
    boolean ret = queue.remove(arg0);
    set.remove(arg0);
    return ret;
}

@Override public boolean removeAll(Collection<?> arg0) {
    boolean ret = queue.removeAll(arg0);
    set.removeAll(arg0);
    return ret;
}

@Override public void clear() {
    set.clear();
    queue.clear();
}

@Override public boolean contains(Object arg0) {
    return set.contains(arg0);
}

@Override public boolean containsAll(Collection<?> arg0) {
    return set.containsAll(arg0);
}

@Override public boolean isEmpty() {
    return set.isEmpty();
}

@Override public Iterator<T> iterator() {
    return queue.iterator();
}

@Override public boolean retainAll(Collection<?> arg0) {
    throw new UnsupportedOperationException();
}

@Override public int size() {
    return queue.size();
}

@Override public Object[] toArray() {
    return queue.toArray();
}

@Override public <T> T[] toArray(T[] arg0) {
    return queue.toArray(arg0);
}

@Override public T element() {
    return queue.element();
}

@Override public boolean offer(T e) {
    return queue.offer(e);
}

@Override public T peek() {
    return queue.peek();
}

@Override public T poll() {
    return queue.poll();
}
}
Run Code Online (Sandbox Code Playgroud)

  • 如果用 ArrayDeque 替换 LinkedList,您将获得比 LinkedHashSet 更好的轮询性能 (x2),并且也应该击败您的实现。这是一篇比较实现的博客文章:http://psy-lob-saw.blogspot.com/2013/03/merging-queue-arraydeque-and-suzie-q.html (3认同)
  • 队列方法与 set 方法不同步,例如 poll() 还应该从集合中删除元素,否则可能会发生您在代码中的某个地方询问 !isEmpty() ,然后当您调用 poll() 时它结果是 NPE。 (2认同)