Une file d'attente qui assure l'unicité des éléments?

je cherche une implémentation de java.util.File d'attente ou quelque chose dans la collection Google qui se comporte comme une file d'attente, mais aussi s'assurer que chaque élément de la file d'attente est unique. (toute insertion ultérieure n'aura aucun effet)

C'est possible, ou devrai-je le faire à la main?

pour l'instant j'utilise une file d'attente, avec une implémentation LinkedList, et je vérifie l'unicité avant l'insertion. (J'utilise une carte de côté pour ce faire, Ajouter / Supprimer élément du côté de la carte avant / après la queu ). Je ne l'aime pas trop.

toute entrée est la bienvenue. Si ce n'est pas dans la java.le paquet util, alors c'est peut-être une mauvaise idée?

53
demandé sur Antoine Claval 2010-02-23 18:01:25

7 réponses

Que diriez-vous d'un LinkedHashSet ? Son itérateur préserve l'ordre d'insertion, mais comme c'est un Set , ses éléments sont uniques.

comme le dit sa documentation,

noter que l'ordre d'insertion est et non si un élément est ré-inséré dans l'ensemble.

afin d'éliminer efficacement les éléments chef de file d'attente, passez par son itérateur:

Iterator<?> i = queue.iterator();
...
Object next = i.next();
i.remove();
41
répondu erickson 2010-02-23 15:16:09

cela n'existe pas autant que je sache mais serait assez simple à mettre en œuvre en utilisant un LinkedList en conjonction avec un 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.
}
20
répondu Adamski 2010-02-23 15:08:31

vérifier l'unicité a bien sûr un coût (dans l'espace ou dans le temps). Il semble qu'il pourrait être intéressant de travailler à partir de quelque chose comme Unequeue de priorité qui maintiendra un tas trié par comparateur des éléments. Vous pourriez être en mesure de tirer parti de cela pour plus efficacement (o(log n)) vérifier l'existence sans maintenir une carte de côté.

si vous souhaitez envelopper une file d'attente avec un vérificateur d'unicité, je recommande fortement d'utiliser les Collections Google ForwardingQueue pour construire une telle chose.

4
répondu Alex Miller 2010-02-23 15:12:28

juste pour compléter la réponse D'Adamski:

/**
 * 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();
}
}
3
répondu Erel Segal-Halevi 2013-04-01 11:20:33

C'est une très bonne question. Il n'existe pas de solution simple. Je vais déterrer un code que j'ai écrit il y a quelques temps qui a tenté de faire ça, et revenir et éditer cette réponse.

EDIT: je suis de retour. En vérité, si vous n'avez pas besoin de la concurrence, vous êtes mieux de maintenir une file d'attente et mis séparément. Pour ce que je faisais, la concurrence était un objectif, mais la meilleure solution que j'ai pu trouver étant donné que la contrainte était problématique; fondamentalement, puisqu'il a utilisé un Competienthashmap, plus vous retiriez l'élément "tête" de la file (une chose de base à faire avec une file), plus déséquilibré la table de hachage deviendrait au fil du temps. Je peux encore partager ce code avec toi, mais je doute que tu le veuilles vraiment.

modifier: pour le cas où la concurrence est requise j'ai donné cette réponse: Simultaneous Set Queue

1
répondu Kevin Bourrillion 2017-05-23 11:47:32

Malheureusement, il n'existe pas. Depuis que j'ai eu besoin d'une telle file d'attente, j'ai développé une file D'attente de blocage soutenue par un ensemble, inspiré de java.util.simultané.LinkedBlockingQueue .

vous pouvez le trouver ici:

https://github.com/bvanalderweireldt/concurrent-unique-queue

exemple:

final BlockingQueue<Integer> queue = new ConcurrentSetBlockingQueue<>(1);
queue.offer(new Integer(1)); //True
queue.offer(new Integer(1)); //False

vous pouvez l'utiliser avec Maven :

<dependency>
  <groupId>com.hybhub</groupId>
  <artifactId>concurrent-util</artifactId>
  <version>0.1</version>
</dependency>
1
répondu Benoit Vanalderweireldt 2017-03-21 13:10:16