Biliyorum SortedSetama benim durumumda uygulayan bir şeye ihtiyacım var List, değil Set. Öyleyse orada, API'de veya başka bir yerde bir uygulama var mı?
Kendimi uygulamak zor olmamalı, ama neden önce buradaki insanlara sormayacağımı düşündüm.
Biliyorum SortedSetama benim durumumda uygulayan bir şeye ihtiyacım var List, değil Set. Öyleyse orada, API'de veya başka bir yerde bir uygulama var mı?
Kendimi uygulamak zor olmamalı, ama neden önce buradaki insanlara sormayacağımı düşündüm.
Yanıtlar:
Standart kitaplıkta bunu yapmak için Java koleksiyonu yoktur. LinkedHashSet<E>sıralamayı a'ya benzer şekilde korur List, bu nedenle kümenizi bir Listolarak kullanmak istediğinizde bir kümeye sararsanız, istediğiniz Listanlam bilgisini elde edersiniz.
Alternatif olarak, Commons Koleksiyonları (veya commons-collections4genel sürüm için) Listzaten istediğinizi yapan bir şeye sahiptir : SetUniqueList/ SetUniqueList<E>.
İşte yaptığım şey ve işe yarıyor.
Çalışmam gerektiğini varsayarsak, yaptığım ArrayListilk şey yeni bir şey yaratmaktı LinkedHashMap.
LinkedHashSet<E> hashSet = new LinkedHashSet<E>()
Sonra yeni öğemi LinkedHashSet. LinkedHasSetYeni öğe bir kopya ise add yöntemi değiştirmez ve yanlış döndürür. Yani bu ArrayList,.
if (hashSet.add(E)) arrayList.add(E);
Bu, kopyaların bir dizi listesine eklenmesini önlemenin basit ve zarif bir yoludur. İsterseniz, onu sarmalayabilir ve add yöntemini ArrayList. addAllÖğeler arasında döngü oluşturarak ve add yöntemini çağırarak uğraşmayı unutmayın .
İşte sonunda yaptığım şey. Umarım bunun bir başkasına yardımı olur.
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);
}
}
}
Neden bir kümeyi bir listeyle sarmalıyorsunuz, şöyle sıralayın:
new ArrayList( new LinkedHashSet() )
Bu, gerçek bir Koleksiyon ustası olan biri için diğer uygulamayı bırakır ;-)
Dhiller'ın cevabını ciddiye almalısınız:
new ArrayList(set)(veya a new LinkedList(set), her neyse) içine sarın .Bence yayınladığınız çözümün NoDuplicatesList, çoğunlukla contains()yöntemle ilgili bazı sorunları olduğunu düşünüyorum , ayrıca sınıfınız, addAll()yönteminize aktarılan Koleksiyondaki kopyaları kontrol etmiyor .
Bunun gibi bir şeye ihtiyacım vardı, bu yüzden ortak koleksiyonlara gittim ve kullandım SetUniqueList, ancak bazı performans testleri çalıştırdığımda, a kullanmak Setve Arraykullanarak bir elde etmek istersem, duruma göre optimize edilmediğini gördüm .Set.toArray() yöntemi .
SetUniqueTestAldı 1 kez: 20 çapraz sonra doldurmak ve 100.000 dizeleri büyük bir anlaşma farkıdır diğer uygulama, karşılaştırarak.
Performansta dert varsa yani, ben kullanmayı tavsiye Set ve Array alın kullanmak yerine SetUniqueListgerçekten mantığını gerekmiyorsa SetUniqueList, o zaman başka çözümler kontrol etmek gerekir ...
Test kodu ana yöntemi :
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
}
Saygılarımızla, Mohammed Sleem
NOT: alt liste uygulamasını dikkate almaz .
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));
}
}
Toplama arayüzleri için dokümantasyon diyor ki:
Set - yinelenen öğeler içeremeyen bir koleksiyon.
Liste - sıralı bir koleksiyon (bazen bir sıra olarak adlandırılır). Listeler yinelenen öğeler içerebilir.
Dolayısıyla, kopyaları istemiyorsanız, muhtemelen bir liste kullanmamalısınız.
içinde addyöntemle, neden kullanmayan HashSet.add()yerine çiftleri kontrol etmek HashSet.consist().
kopya yoksa HashSet.add()geri dönecektir .truefalse
HashSet#consist()?
Aklımın ucunda, listeler kopyalara izin veriyor. Devralınan yöntemleri çağırmadan önce kontrol etmek için hızlı bir şekilde a uygulayabilir UniqueArrayListve tüm add/ insertişlevlerini geçersiz kılabilirsiniz contains(). Kişisel kullanım için, yalnızca addkullandığınız yöntemi uygulayabilir ve gelecekteki programcıların listeyi farklı bir şekilde kullanmaya çalışması durumunda bir istisna atmak için diğerlerini geçersiz kılabilirsiniz.
Kendi küçük kütüphanemde şu şekilde kendi UniqueList'imi oluşturdum:
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;
}
}
Şuna benzeyen bir TestCollections sınıfım var:
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);
}
}
İyi çalışıyor. Yaptığı tek şey, zaten yoksa ve iade edilebilir bir Dizi Listesi ve bir nesne dizisi varsa, bir kümeye ekleme yapmaktır.