Есть ли там реализация списка без дубликатов?
Я знаю, о SortedSet
, но в моем случае мне нужно что-то, что реализует List
, а не Set
. Так есть ли реализация там, в API или в другом месте?
Это не должно быть трудно реализовать себя, но я подумал, почему бы не спросить людей здесь впервые?
11 ответов:
в стандартной библиотеке нет коллекции Java для этого.
LinkedHashSet<E>
сохраняет порядок аналогично aList
, хотя, так что если вы обернуть вList
когда вы хотите использовать его какList
вы получите семантику, которую вы хотите.кроме того,Викискладе Коллекции (или
commons-collections4
, для общей версии) имеетList
который делает то, что вы уже хотите:SetUniqueList
/SetUniqueList<E>
.
вот что я сделал и это работает.
предполагая, что у меня есть
ArrayList
для работы с первым, что я сделал был создан новыйLinkedHashMap
.LinkedHashSet<E> hashSet = new LinkedHashSet<E>()
затем я пытаюсь добавить новый элемент
LinkedHashSet
. Метод add не изменяетLinkedHasSet
и возвращает false, если новый элемент является дубликатом. Так что это становится условием, которое я могу проверить перед добавлением вArrayList
.if (hashSet.add(E)) arrayList.add(E);
это простой и элегантный способ, чтобы предотвратить дубликаты от добавлен в список массивов. Если вы хотите, вы можете инкапсулировать его и переопределить метод add в классе, который расширяет
ArrayList
. Просто не забудьте разобраться сaddAll
путем циклического перебора элементов и вызова метода add.
Так вот что я сделал в конце концов. Я надеюсь, что это поможет кому-то еще.
class NoDuplicatesList<E> extends LinkedList<E> { @Override public boolean add(E e) { if (this.contains(e)) { return false; } else { return super.add(e); } } @Override public boolean addAll(Collection<? extends E> collection) { Collection<E> copy = new LinkedList<E>(collection); copy.removeAll(this); return super.addAll(copy); } @Override public boolean addAll(int index, Collection<? extends E> collection) { Collection<E> copy = new LinkedList<E>(collection); copy.removeAll(this); return super.addAll(index, copy); } @Override public void add(int index, E element) { if (this.contains(element)) { return; } else { super.add(index, element); } } }
вы должны серьезно рассмотреть ответ диллера:
- вместо того, чтобы беспокоиться о добавлении ваших объектов в список без дубликатов, добавьте их в набор (любую реализацию), который по своей природе будет отфильтровывать дубликаты.
- когда вам нужно вызвать метод, который требует список, оберните его в
new ArrayList(set)
(илиnew LinkedList(set)
и т. д.).Я думаю, что решение вы разместили с
NoDuplicatesList
есть некоторые проблемы, в основном сcontains()
способ, кроме того, ваш класс не обрабатывает проверку на наличие дубликатов в коллекции, переданной вашемуaddAll()
метод.
почему бы не инкапсулировать набор со списком, например:
new ArrayList( new LinkedHashSet() )
Это оставляет другую реализацию для кого-то, кто является настоящим мастером коллекций; -)
Мне нужно было что-то вроде этого, поэтому я пошел в коллекции commons и использовал SetUniqueList, но когда я запустил какой-то тест производительности, я обнаружил, что он кажется не оптимизированным по сравнению с тем, если я хочу использовать набор и получить массив с помощью набора.метод toArray (), SetUniqueTest занял 20: 1 время, чтобы заполнить, а затем пересечь 100 000 строк по сравнению с другой реализацией, что является большой разницей, поэтому, если вы беспокоитесь о производительности, я рекомендую вам использовать набор и получить массив вместо использования SetUniqueList, если вам действительно не нужна логика SetUniqueList, то вам нужно проверить другие решения...
основной метод тестирования кода:
public static void main (String[] args) {
SetUniqueList pq = SetUniqueList.decorate(new ArrayList()); Set s = new TreeSet(); long t1 = 0L; long t2 = 0L; String t; t1 = System.nanoTime(); for (int i = 0; i < 200000; i++) { pq.add("a" + Math.random()); } while (!pq.isEmpty()) { t = (String) pq.remove(0); } t1 = System.nanoTime() - t1; t2 = System.nanoTime(); for (int i = 0; i < 200000; i++) { s.add("a" + Math.random()); } s.clear(); String[] d = (String[]) s.toArray(new String[0]); s.clear(); for (int i = 0; i < d.length; i++) { t = d[i]; } t2 = System.nanoTime() - t2; System.out.println((double)t1/1000/1000/1000); //seconds System.out.println((double)t2/1000/1000/1000); //seconds System.out.println(((double) t1) / t2); //comparing results
}
С уважением Мохаммед Слим http://abusleem.net/blog
Примечание: он не принимает подсписок реализация во внимание.
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Set; public class UniqueList<T> extends ArrayList<T> { private static final long serialVersionUID = 1L; /** Unique elements SET */ private final Set<T> set=new HashSet(); /** Used by addAll methods */ private Collection<T> addUnique(Collection<? extends T> col) { Collection<T> unique=new ArrayList(); for(T e: col){ if (set.add(e)) unique.add(e); } return unique; } @Override public boolean add(T e) { return set.add(e) ? super.add(e) : false; } @Override public boolean addAll(Collection<? extends T> col) { return super.addAll(addUnique(col)); } @Override public void add(int index, T e) { if (set.add(e)) super.add(index, e); } @Override public boolean addAll(int index, Collection<? extends T> col) { return super.addAll(index, addUnique(col)); } }
The документация для интерфейсов сбора говорит:
Set-коллекция, которая не может содержать повторяющиеся элементы.
Список-упорядоченная коллекция (иногда называемая последовательностью). Списки могут содержать повторяющиеся элементы.Так что если вы не хотите дубликатов, вы, вероятно, не должны использовать список.
на
add
способ, почему бы не использоватьHashSet.add()
чтобы проверить дубликаты вместоHashSet.consist()
.HashSet.add()
вернутсяtrue
если нет дубликатов иfalse
в противном случае.
С верхней части моей головы, списки разрешить дубликаты. Вы можете быстро реализовать
UniqueArrayList
и переопределить всеadd
/insert
функции для проверкиcontains()
перед вызовом унаследованных методов. Для личного использования вы можете реализовать толькоadd
метод, который вы используете, и переопределить другие, чтобы бросить исключение в случае, если будущие программисты пытаются использовать список по-другому.
Я только что сделал свой собственный уникальный список в моей собственной маленькой библиотеке, как это:
package com.bprog.collections;//my own little set of useful utilities and classes import java.util.HashSet; import java.util.ArrayList; import java.util.List; /** * * @author Jonathan */ public class UniqueList { private HashSet masterSet = new HashSet(); private ArrayList growableUniques; private Object[] returnable; public UniqueList() { growableUniques = new ArrayList(); } public UniqueList(int size) { growableUniques = new ArrayList(size); } public void add(Object thing) { if (!masterSet.contains(thing)) { masterSet.add(thing); growableUniques.add(thing); } } /** * Casts to an ArrayList of unique values * @return */ public List getList(){ return growableUniques; } public Object get(int index) { return growableUniques.get(index); } public Object[] toObjectArray() { int size = growableUniques.size(); returnable = new Object[size]; for (int i = 0; i < size; i++) { returnable[i] = growableUniques.get(i); } return returnable; } }
у меня есть класс TestCollections, который выглядит так:
package com.bprog.collections; import com.bprog.out.Out; /** * * @author Jonathan */ public class TestCollections { public static void main(String[] args){ UniqueList ul = new UniqueList(); ul.add("Test"); ul.add("Test"); ul.add("Not a copy"); ul.add("Test"); //should only contain two things Object[] content = ul.toObjectArray(); Out.pl("Array Content",content); } }
работает нормально. Все, что он делает, это добавляет к набору, если у него его еще нет, и есть ArrayList, который можно вернуть, а также массив объектов.