Я знаю о SortedSet
, но в моем случае мне нужно что-то, что реализует List
, а не Set
. Так есть ли реализация там, в API или где-то еще?
Нельзя было бы реализовать себя, но я решил, почему сначала не спрашивать людей здесь?
Я знаю о SortedSet
, но в моем случае мне нужно что-то, что реализует List
, а не Set
. Так есть ли реализация там, в API или где-то еще?
Нельзя было бы реализовать себя, но я решил, почему сначала не спрашивать людей здесь?
В стандартной библиотеке нет коллекции Java. LinkedHashSet<E>
сохраняет упорядочение аналогично List
, поэтому, если вы завернете свой набор в List
, когда хотите использовать это как List
вы получите семантику, которую хотите.
В качестве альтернативы Commons Collections (или commons-collections4
для общей версии) имеет List
, который делает то, что вы хотите уже: SetUniqueList
/SetUniqueList<E>
.
Итак, вот что я сделал в конце концов. Надеюсь, это поможет кому-то другому.
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);
}
}
}
Вот что я сделал, и он работает.
Предполагая, что у меня есть ArrayList
для работы с первым, что я сделал, был создан новый LinkedHashMap
.
LinkedHashSet<E> hashSet = new LinkedHashSet<E>()
Затем я пытаюсь добавить свой новый элемент в LinkedHashSet
. Метод добавления не изменяет LinkedHasSet
и возвращает false, если новый элемент является дубликатом. Таким образом, это условие, которое я могу проверить перед добавлением в ArrayList
.
if (hashSet.add(E)) arrayList.add(E);
Это простой и элегантный способ предотвратить добавление дубликатов в список массивов. Если вы хотите, вы можете инкапсулировать его и переопределить метод add в классе, который расширяет ArrayList
. Просто помните, что нужно иметь дело с addAll
, перейдя через элементы и вызывая метод добавления.
Вы должны серьезно рассмотреть ответ dhiller:
new ArrayList(set)
(или a new LinkedList(set)
, что угодно).Я думаю, что решение, которое вы разместили с NoDuplicatesList
, имеет некоторые проблемы, в основном с помощью метода contains()
, а также ваш класс не обрабатывает проверку дубликатов в коллекции, переданной вашему методу addAll()
.
Почему бы не инкапсулировать набор со списком, вроде как:
new ArrayList( new LinkedHashSet() )
Это оставляет другую реализацию для кого-то, кто является настоящим мастером коллекций; -)
Мне нужно было что-то вроде этого, поэтому я пошел в коллекцию commons и использовал SetUniqueList, но когда я запустил некоторый тест производительности, я обнаружил, что он не оптимизирован по сравнению с случаем, если я хочу использовать Set и получить Массив с использованием метода Set.toArray(), SetUniqueTest занял 20: 1 раз, чтобы заполнить, а затем пересечь 100 000 строк по сравнению с другой реализацией, что является большой разницей, поэтому, если вы беспокоитесь об эффективности, я рекомендую вам использовать Set и получить 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
}
Отношения Мохаммед Слейм http://abusleem.net/blog
Документация для интерфейсов коллекции:
Set - коллекция, которая не может содержать повторяющиеся элементы.
Список - упорядоченная коллекция (иногда называемая последовательностью). Списки могут содержать повторяющиеся элементы.
Итак, если вы не хотите дубликатов, вы, вероятно, не должны использовать список.
Сверху моей головы списки позволяют дублировать. Вы можете быстро реализовать UniqueArrayList
и переопределить все функции add
/insert
, чтобы проверить contains()
перед вызовом унаследованных методов. Для личного использования вы можете использовать только метод add
, который вы используете, и переопределить остальные, чтобы исключить исключение, если будущие программисты попытаются использовать список другим способом.
в add
, почему бы не использовать HashSet.add()
для проверки дубликатов вместо HashSet.consist()
.
HashSet.add()
вернет true
, если нет дубликата и false
в противном случае.
ПРИМЕЧАНИЕ. В него не включена реализация subList.
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));
}
}
Я просто сделал свой собственный 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, а также массив объектов.