Знаю SortedSet, но в моем случае мне нужно то, что реализует List, а нет Set. Так есть ли там реализация, в API или где-то еще?
Это не должно быть сложно реализовать, но я подумал, почему бы сначала не спросить здесь людей?
Знаю SortedSet, но в моем случае мне нужно то, что реализует List, а нет Set. Так есть ли там реализация, в API или где-то еще?
Это не должно быть сложно реализовать, но я подумал, почему бы сначала не спросить здесь людей?
Ответы:
Для этого в стандартной библиотеке нет коллекции Java. однако LinkedHashSet<E>сохраняет порядок, аналогично a List, поэтому, если вы оберните свой набор в a, Listкогда вы хотите использовать его как a, Listвы получите желаемую семантику.
В качестве альтернативы, Коллекции Commons (или 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циклом по элементам и вызывать метод добавления.
Итак, вот что я в итоге сделал. Надеюсь, это поможет кому-то другому.
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( new LinkedHashSet() )
Остается другая реализация для тех, кто является настоящим мастером коллекций ;-)
Вам следует серьезно обдумать ответ Дхиллера:
new ArrayList(set)(или в new LinkedList(set)любой другой).Я думаю, что решение, которое вы опубликовали с помощью, NoDuplicatesListимеет некоторые проблемы, в основном с contains()методом, плюс ваш класс не обрабатывает проверку дубликатов в коллекции, переданной вашему addAll()методу.
Мне нужно было что-то подобное, поэтому я пошел в общие коллекции и использовал SetUniqueList, но когда я провел некоторый тест производительности, я обнаружил, что он не оптимизирован по сравнению со случаем, если я хочу использовать Setи получить с Arrayпомощью Set.toArray()метода.
Для заполнения и последующего прохождения 100000 строкSetUniqueTest потребовалось 20: 1 времени по сравнению с другой реализацией, что является большой разницей.
Итак, если вы беспокоитесь о производительности, я рекомендую вам использовать Set и Get a Array вместо использования 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
}
С уважением, Мохаммед Слим
ПРИМЕЧАНИЕ: он не принимает во внимание реализацию подсписка .
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));
}
}
В документации для интерфейсов сбора говорится:
Set - коллекция, не содержащая повторяющихся элементов.
Список - упорядоченная коллекция (иногда называемая последовательностью). Списки могут содержать повторяющиеся элементы.
Поэтому, если вам не нужны дубликаты, вам, вероятно, не следует использовать список.
in add, почему бы не использовать HashSet.add()для проверки дубликатов вместо HashSet.consist().
HashSet.add()вернется, trueесли нет дубликатов и в falseпротивном случае.
HashSet#consist()?
Вне моей головы списки допускают дублирование. Вы можете быстро реализовать UniqueArrayListи переопределить все функции add/ insertдля проверки contains()перед вызовом унаследованных методов. Для личного использования вы можете реализовать только тот addметод, который используете, и переопределить другие, чтобы генерировать исключение на случай, если будущие программисты попытаются использовать список по-другому.
Я только что создал свой собственный список UniqueList в своей небольшой библиотеке, вот так:
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, а также массив объектов.