Kolejka zapewniająca unikalność elementów?

Szukam implementacji Javy.util.Kolejka lub coś w kolekcji Google, którzy zachowują się jak Kolejka, ale także upewnić się, że każdy element kolejki jest unikalny. (wszystkie dalsze wstawianie nie będzie miało wpływu)

To możliwe, czy będę musiał to zrobić ręcznie?

Na razie używam kolejki z implementacją LinkedList i sprawdzam unikalność przed wstawieniem. ( Do tego celu używam mapy bocznej, dodaję / usuwam element z mapy bocznej przed / po Kolejka). Nie podoba mi się to za bardzo.

Każdy wkład jest mile widziany. Jeśli nie jest w Javie.pakiet util, to może to zły pomysł?

Author: Antoine Claval, 2010-02-23

7 answers

A może LinkedHashSet? Iterator zachowuje porządek wstawiania, ale ponieważ jest Set, jego elementy są unikalne.

Jak mówi dokumentacja,

Należy zauważyć, że kolejność wstawiania nie ma wpływu na , Jeśli element jest ponownie wstawiony do zbioru.

Aby efektywnie usunąć elementy z głowy tej "kolejki", przejdź przez iterator:

Iterator<?> i = queue.iterator();
...
Object next = i.next();
i.remove();
 41
Author: erickson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-23 15:16:09

To nie istnieje, o ile wiem, ale byłoby dość proste do zaimplementowania przy użyciu LinkedList w połączeniu z 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
Author: Adamski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-23 15:08:31

Chciałbym zachować HashSet zawierający klucz, który jednoznacznie identyfikuje elementy w kolejce obok siebie. Następnie po prostu sprawdź HashSet, aby sprawdzić, czy element znajduje się w kolejce przed dodaniem go. Gdy usuniesz element z kolejki, po prostu usuń klucz z HashSet.

 4
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-23 15:05:11

Sprawdzanie wyjątkowości oczywiście wiąże się z kosztami (zarówno w przestrzeni, jak i w czasie). Wydaje się, że może być interesująca praca z czymś takim jak PriorityQueue, który utrzyma stertę posortowaną według komparatora elementów. Być może będziesz w stanie wykorzystać to do bardziej wydajnego (o(log n)) sprawdzania istnienia bez utrzymywania mapy bocznej.

Jeśli chcesz zawinąć kolejkę za pomocą sprawdzania unikalności, zdecydowanie polecam użycie kolekcji Google ForwardingQueue do budowania coś takiego.

 4
Author: Alex Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-23 15:12:28

Żeby uzupełnić odpowiedź Adamskiego:

/**
 * 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
Author: Erel Segal-Halevi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-01 11:20:33

To bardzo dobre pytanie. Nie istnieje żadne proste rozwiązanie. Wykopię jakiś kod, który jakiś czas temu próbował to zrobić, i wrócę i edytuję tę odpowiedź.

EDIT: wróciłem. Naprawdę, jeśli nie potrzebujesz współbieżności, lepiej zachowaj kolejkę i ustaw osobno. Dla tego, co robiłem, współbieżność była celem, ale najlepsze rozwiązanie, jakie mogłem wymyślić, biorąc pod uwagę, że ograniczenie było problematyczne; zasadniczo, ponieważ używało ConcurrentHashMap, im bardziej usuwałeś element "head" z kolejki (podstawowa rzecz związana z kolejką), tym z czasem stała się bardziej niezrównoważona tabela hash. Nadal mogę podzielić się z Tobą tym kodem, ale wątpię, czy naprawdę tego chcesz.

EDIT: W przypadku gdy wymagana jest współbieżność dałem taką odpowiedź: Kolejka Zestawów Współbieżnych

 1
Author: Kevin Bourrillion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32

Niestety nie istnieje. Ponieważ potrzebowałem takiej kolejki, opracowałem kolejkę blokującą wspieraną przez Zestaw, zainspirowany java.util./ align = "left" / LinkedBlockingQueue .

Znajdziesz go tutaj:

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

Przykład:

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

Możesz go używać z Maven:

<dependency>
  <groupId>com.hybhub</groupId>
  <artifactId>concurrent-util</artifactId>
  <version>0.1</version>
</dependency>
 1
Author: Benoit Vanalderweireldt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-21 13:10:16