क्या कोई डुप्लिकेट सूची लागू नहीं है?


86

मुझे इसके बारे में पता है SortedSet, लेकिन मेरे मामले में मुझे ऐसी किसी चीज़ की ज़रूरत है जो लागू हो List, और नहीं Set। तो क्या वहाँ एक कार्यान्वयन है, एपीआई या कहीं और?

अपने आप को लागू करना कठिन नहीं होना चाहिए, लेकिन मुझे लगा कि पहले यहां के लोगों से क्यों नहीं पूछा गया?


1
सूची को लागू करने की आवश्यकता क्यों है? सेट सूची की तरह पुनरावृत्त होते हैं, इसलिए मुझे लगता है कि प्राप्त करने की विधि किसी अन्य कारण से सूची लागू कर रही है।
रोब

@ रब यह सही है, यह एक बाहरी मांग है, और डेटा संरचना में एक से अधिक सूची का एक नरक शामिल है।
युवल

यदि उपयोगकर्ता एक LIST चाहता है, तो यह स्पष्ट है कि LIST इंटरफ़ेस के तरीकों की आवश्यकता है जो um SET इंटरफ़ेस मौजूद नहीं है ...
marcolopes

जवाबों:


92

ऐसा करने के लिए मानक पुस्तकालय में कोई जावा संग्रह नहीं है। हालांकि, यदि आप अपना सेट लपेटते हैं, तो जब आप इसका उपयोग करना चाहते हैं, तो आप इसे LinkedHashSet<E>उसी तरह से ऑर्डर कर सकते हैं, जैसा कि आप चाहते हैं कि आपको शब्दार्थ मिलेगा।ListListList

वैकल्पिक रूप से, कॉमन्स कलेक्शंस (या commons-collections4, जेनेरिक संस्करण के लिए) में एक Listऐसा है जो आप पहले से ही चाहते हैं: SetUniqueList/ SetUniqueList<E>


5
कॉमन्स वर्ग वास्तव में वही है जो मुझे चाहिए, लेकिन मेरे बॉस ने मुझे खुद इसे अंततः लागू करने के लिए कहा। वैसे भी 10x!
युवल

5
आह ठीक है, पहिए को फिर से लगाने जैसा कुछ नहीं! अब आपको पता चल जाएगा कि क्या जरूरत फिर से बढ़ जाती है, वैसे भी। संग्रह 15 एक बहुत उपयोगी चीज है जिसके चारों ओर लात मारना है; मल्टीपैप्स विशेष रूप से किसी चीज के दर्द को कम करते हैं, जिससे खुद को बहुत अधिक लागू करना पड़ता है।
कालुम

19
@skaffman: वह वास्तव में एक मूर्ख नहीं है, लेकिन कभी-कभी वह चालें बनाता है जो कि ... अच्छी तरह से, अजीब हैं। वैसे भी, मैं उत्पाद में बग का परिचय नहीं देने वाला हूं। आज के बाजार में, मैं अपनी नौकरी से खुश हूं और मेरे दरवाजे पर अगर आप मेरी बात मानते हैं तो दरवाजे और पुल को जलाने के लिए नहीं।
युवल

3
मुझे बहुत आश्चर्य हुआ जब SetUniqueList में पैरामीटर प्रकार नहीं है।
पन्नाधाय

2
जेफरी: मोबाइल प्लेटफॉर्म्स पर सिस्टम आमतौर पर अप्रयुक्त कक्षाओं को हटा देगा, लेकिन निश्चित रूप से, बहुत सारे कारण हैं जो आप इन "सामान्य" समाधानों में से एक के नीचे नहीं जा सकते हैं। हमेशा कुछ व्यापार बंद किया जाना चाहिए, और कोई समाधान सभी मामलों को ठीक नहीं करेगा।
कलुम

14

यहाँ मैंने क्या किया और यह काम करता है।

यह मानते हुए कि मेरे पास ArrayListपहले काम करने के लिए एक नया काम था LinkedHashMap

LinkedHashSet<E> hashSet = new LinkedHashSet<E>()

फिर मैं अपने नए तत्व को जोड़ने का प्रयास करता हूं LinkedHashSetLinkedHasSetयदि नया तत्व डुप्लिकेट है, तो ऐड मेथड में परिवर्तन नहीं होता है और यह गलत हो जाता है। तो यह एक शर्त बन जाती है जिसे मैं जोड़ने से पहले परीक्षण कर सकता हूं ArrayList

if (hashSet.add(E)) arrayList.add(E);

यह एक सरल और सुरुचिपूर्ण तरीका है जो डुप्लिकेट को एक सरणी सूची में जोड़े जाने से रोकने के लिए है। यदि आप चाहते हैं कि आप इसे एक वर्ग में ऐड मेथड को इनकैप्सुलेट और ओवरराइड कर सकते हैं जो फैली हुई है ArrayList। बस addAllतत्वों के माध्यम से लूपिंग और ऐड पद्धति को कॉल करने से निपटने के लिए याद रखें ।


1
हाँ, मुझे लगता है, यह इसके लिए सबसे अच्छा समाधान है, आप बस एक सामान्य हैशसेट का उपयोग कर सकते हैं, एक लिंक्ड का उपयोग नहीं कर सकते हैं, और फिर आप अपनी सूची का उपयोग कर सकते हैं जैसा आप चाहते हैं, आप कुछ स्थितियों में क्या करना चाहते हैं, जैसे भी कर सकते हैं किसी विशिष्ट इंडेक्स से पहले सूची के अंदर एक तत्व जोड़ना, आप यह निर्धारित कर सकते हैं कि आप डुप्लिकेट किए गए आइटम को इस स्थिति में ले जाना चाहते हैं या नहीं।
ग्युरिक्स

यहां सबसे अच्छा समाधान ... मेरी यूनीकलिस्ट क्लास कोड
मार्कोलोप्स

यह मेरे लिए, मेरे बीएफएस ग्राफ एल्गोरिथ्म में काम किया। क्योंकि मेरे पास कुछ नोड्स थे जिन्हें मैंने एक कतार (लिंक्डलिस्ट) में जोड़ा था, अगर वे पहले से ही अंदर नहीं थे।
जीनकार्लो फानाल्टो

11

इसलिए यहां मैंने आखिरकार क्या किया। मैं उम्मीद करता हूं कि इससे किसी की मदद होगी।

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);
        }
    }
}   

10
सावधान रहें - LinkedList.contains () को यह निर्धारित करने के लिए पूरी सूची को स्कैन करने की आवश्यकता है कि कोई वस्तु सूची में निहित है या नहीं। इसका मतलब है कि जब आप बड़ी सूची में वस्तुओं को जोड़ रहे हैं, तो पूरी सूची को प्रत्येक ऐड ऑपरेशन (सबसे खराब स्थिति में) के लिए स्कैन किया जाता है। यह धीरे-धीरे कम हो सकता है।
मैट बी

8
इसके अलावा, आपके ऐडऑल ओवरराइड को एडऑल () में पारित होने वाले संग्रह में डुप्लिकेट के लिए जांच नहीं करता है।
मैट बी

@mattb तब आप इस समस्या को कैसे हल करेंगे: Android पर, जब वस्तुओं को किसी सूची आइटम दृश्य से जोड़ते हैं, तो हमें दृश्य एडाप्टर में आइटम की स्थिति दी जाती है। चूँकि सेटों में कोई इंडेक्स नहीं है, लिस्ट का उपयोग करते समय ऑब्जेक्ट मौजूद है या नहीं, इसकी जाँच करने का एकमात्र तरीका मौजूदा कॉपी की खोज करना है।
TheRealChx101

6

सूची के साथ सेट को क्यों नहीं अलग करना चाहिए, जैसे:

new ArrayList( new LinkedHashSet() )

यह किसी ऐसे व्यक्ति के लिए अन्य कार्यान्वयन को छोड़ देता है जो संग्रह का वास्तविक स्वामी है; ;-)


4
यह कंस्ट्रक्टर सेट की सामग्री को लपेटने के बजाय नई सूची में कॉपी करता है।
कैलुम

@ कैलम, यह सही है, लेकिन डुप्लिकेट को किसी सूची में नहीं जोड़ने के बारे में चिंता करने के बजाय, वह अपनी वस्तुओं को सेट में जोड़ सकता है (और डुप्लिकेट को फ़िल्टर करने के बारे में सेट चिंता करने दें) और बस इसे पास करते समय एक सूची में सेट करें। बाहरी विधि।
मैट बी

4
यह एक सेट को एक सूची में कॉपी करता है लेकिन आपके पास कोई प्रसिद्ध आदेश नहीं है। लेकिन यह सवाल क्या है।
Janning

4

आपको गंभीरता से ढोलक के जवाब पर विचार करना चाहिए:

  1. अपनी वस्तुओं को डुप्लिकेट-कम सूची में जोड़ने के बारे में चिंता करने के बजाय, उन्हें एक सेट (किसी भी कार्यान्वयन) में जोड़ें, जो कि प्रकृति को डुप्लिकेट को फ़िल्टर कर देगा।
  2. जब आपको उस विधि को कॉल करने की आवश्यकता होती है जिसे सूची की आवश्यकता होती है, तो उसे new ArrayList(set)(या ए new LinkedList(set), जो भी) लपेटें ।

मुझे लगता है कि आपके द्वारा पोस्ट किए गए समाधान NoDuplicatesListमें कुछ समस्याएं हैं, ज्यादातर contains()विधि के साथ , साथ ही आपकी कक्षा आपके addAll()तरीके से पारित संग्रह में डुप्लिकेट के लिए जाँच नहीं करती है ।


मैं इनमें से सीखना पसंद करूंगा () मुद्दे। AddAll () के लिए, मैं दिए गए संग्रह की एक प्रति बनाता हूं और 'यह' में पहले से मौजूद सभी वस्तुओं को हटा देता हूं। यह कैसे डुप्लिकेट को संभाल नहीं करता है?
युवल

जैसा कि मैंने आपकी कक्षा की पोस्टिंग में अपनी टिप्पणी में उल्लेख किया है, इसमें यह पाया गया है कि क्या वस्तु में सूची में निहित वस्तु है या नहीं। यदि आपके पास 1 मिलियन आइटमों की सूची है और 10 इसे व्यक्तिगत रूप से जोड़ते हैं, तो (सबसे खराब स्थिति में) दस मिलियन से अधिक आइटम स्कैन किए जाते हैं।
मैट बी

AddAll () के लिए, यदि संग्रह को addAll में दिया गया है, डुप्लिकेट में ही हैं, तो उनका पता नहीं लगाया जाता है। उदाहरण के लिए: आपकी सूची {ए, बी, सी, डी} पैरामीटर सूची {बी, डी, ई, ई, ई}। आप पैरामीटर की एक प्रति बनाते हैं, और हटाने के बाद इसमें {E, E, E} होते हैं।
मैट बी

AddAll () समस्या मेरे लिए वास्तव में प्रासंगिक नहीं है, क्योंकि मैं पूरे प्रक्रिया में NoDuplicatesList का उपयोग करता हूं, और addAll () को अपने पैरामीटर के रूप में एक और NoDuplicatesList प्राप्त करना चाहिए। शामिल () प्रदर्शन को बेहतर बनाने के लिए आप क्या सुझाव देंगे?
युवल Yu

3

मुझे कुछ इस तरह की आवश्यकता थी, इसलिए मैं कॉमन्स संग्रह में गया और इसका इस्तेमाल किया SetUniqueList, लेकिन जब मैंने कुछ प्रदर्शन परीक्षण चलाए, तो मैंने पाया कि यदि मैं एक का उपयोग करना चाहता हूं Setऔर एक विधि Arrayका उपयोग करना चाहता हूं तो यह मामले की तुलना में अनुकूलित नहीं लगता है Set.toArray()

SetUniqueTestले लिया 1 समय: 20 पार भरने के लिए और उसके बाद 1,00,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

}

सादर, मोहम्मद स्लीम


1

ध्यान दें: यह सबलिस्ट कार्यान्वयन को ध्यान में नहीं रखता है।

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));
    }

}

0

संग्रह इंटरफेस के लिए प्रलेखन कहते हैं:

सेट - एक संग्रह जिसमें डुप्लिकेट तत्व नहीं हो सकते।
सूची - एक आदेशित संग्रह (कभी-कभी एक अनुक्रम कहा जाता है)। सूचियों में डुप्लिकेट तत्व हो सकते हैं।

इसलिए यदि आप डुप्लिकेट नहीं चाहते हैं, तो आपको शायद एक सूची का उपयोग नहीं करना चाहिए।


मैंने विशेष रूप से उल्लेख किया है कि मुझे सूची कार्यान्वयन की आवश्यकता है। मेरा विश्वास करो, वहाँ एक कारण है।
युवल

क्या कारण है कि आप एक एपीआई के साथ बातचीत कर रहे हैं जो एक सूची (एक संग्रह के बजाय) को एक पैरामीटर के रूप में ले रहा है। यह थोड़ा परेशान करने के लिए है
मैट बी

दरअसल एपीआई एक मैप <अकाउंटटाइप, मैप <अकाउंटटाइप, लिस्ट <अकाउंट >>> लेता है, जिसका अर्थ है दर्जनों से सैकड़ों लिस्ट के आसपास के क्षेत्र में कहीं न कहीं होल्डिंग ... बीएएच।
युवल

तत्व-प्रायिकता जोड़े के साथ संभाव्यता कार्यों के निर्माण में डुप्लिकेट शामिल नहीं हो सकते हैं, हालांकि डुप्लिकेट तत्वों को केवल विलय किया जा सकता है।
अल जी जॉन्सटन

-1

में addविधि, क्यों उपयोग नहीं कर HashSet.add()के बजाय डुप्लीकेट जांच करने के लिए HashSet.consist()। अगर कोई डुप्लिकेट और नहीं तो HashSet.add()वापस आ जाएगा ।truefalse


क्या है HashSet#consist()?
naXa

-1

मेरे सिर के ऊपर, सूचियाँ डुप्लिकेट की अनुमति देती हैं। आप जल्दी से एक को लागू कर सकता है UniqueArrayListऔर सभी को ओवरराइड add/ insertजांच करने के लिए काम करता है contains()इससे पहले कि आप विरासत में मिला तरीकों कहते हैं। व्यक्तिगत उपयोग के लिए, आप केवल addआपके द्वारा उपयोग की जाने वाली विधि को लागू कर सकते हैं, और भविष्य के प्रोग्रामर द्वारा सूची को अलग तरीके से उपयोग करने का प्रयास करने के मामले में अपवाद को फेंकने के लिए दूसरों को ओवरराइड कर सकते हैं।


मैं इस विचार पर वापस आने के लिए तैयार था (जो अंततः मुझे करना था) अगर किसी ने कुछ भी बेहतर सुझाव नहीं दिया = 8-) ऊपर अपना जवाब देखें।
युवल

-3

मैंने इस तरह से अपनी छोटी सी लाइब्रेरी में सिर्फ अपना खुद का यूनीकलिस्ट बनाया:

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);
    }
}

ठीक काम करता है। यदि यह पहले से ही नहीं है, तो यह एक सेट में जुड़ जाता है और एक एरियर सूची है जो वापस करने योग्य है, साथ ही एक वस्तु सरणी भी है।


हाँ, आपको सूची इंटरफ़ेस को लागू करने के लिए इसमें कुछ और तरीके जोड़ने चाहिए।
ज्युरिक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.