एक सेट से एक तत्व प्राप्त करना


323

Setएक तत्व प्राप्त करने के लिए एक ऑपरेशन क्यों नहीं प्रदान करता है जो किसी अन्य तत्व के बराबर होता है?

Set<Foo> set = ...;
...
Foo foo = new Foo(1, 2, 3);
Foo bar = set.get(foo);   // get the Foo element from the Set that equals foo

मैं पूछ सकता हूं कि क्या Setइसमें एक तत्व समान है bar, इसलिए मुझे वह तत्व क्यों नहीं मिल सकता है? :(

स्पष्ट करने के लिए, equalsविधि को ओवरराइड किया गया है, लेकिन यह केवल एक फ़ील्ड की जांच करता है, सभी नहीं। तो दो Fooवस्तुओं को जो समान माना जाता है, वास्तव में अलग-अलग मूल्य हो सकते हैं, यही कारण है कि मैं सिर्फ उपयोग नहीं कर सकता foo


2
यह पोस्ट पहले से ही व्यापक रूप से चर्चा में है, और अच्छे उत्तर सुझाए गए हैं। हालाँकि, यदि आप केवल एक ऑर्डर किए गए सेट की तलाश कर रहे हैं, तो बस इसका उपयोग करें SortedSetऔर इसके कार्यान्वयन, जो मैप-आधारित हैं (जैसे TreeSetकि एक्सेस करने की अनुमति देता है first())।
एलिरन मलका

3
मुझे वह विधि याद आती है, वह भी ठीक उसी मामले के लिए, जिसका आपने ऊपर वर्णन किया था। ऑब्जेक्टिव-सी ( NSSet) में ऐसी विधि है। इसे कहा जाता है memberऔर यह सेट के भीतर वस्तु को लौटाता है जो "बराबर" memberविधि के पैरामीटर की तुलना करता है (जो कि निश्चित रूप से एक अलग वस्तु हो सकती है और इसमें अलग-अलग गुण भी हो सकते हैं, जो कि बराबर नहीं हो सकता है)।
मकी

जवाबों:


118

तत्व होने की बात नहीं होगी यदि वह समान है। ए Mapइस usecase के लिए बेहतर अनुकूल है।


यदि आप अभी भी उस तत्व को ढूंढना चाहते हैं जिसके पास आपके पास पुनरावृत्ति का उपयोग करने के अलावा और कोई विकल्प नहीं है:

public static void main(String[] args) {

    Set<Foo> set = new HashSet<Foo>();
    set.add(new Foo("Hello"));

    for (Iterator<Foo> it = set.iterator(); it.hasNext(); ) {
        Foo f = it.next();
        if (f.equals(new Foo("Hello")))
            System.out.println("foo found");
    }
}

static class Foo {
    String string;
    Foo(String string) {
        this.string = string;
    }
    @Override
    public int hashCode() { 
        return string.hashCode(); 
    }
    @Override
    public boolean equals(Object obj) {
        return string.equals(((Foo) obj).string);
    }
}

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

14
मैं अभी भी तर्क दूंगा कि यह एक Mapबेहतर ( Map<Foo, Foo>इस मामले में) अनुकूल है
dacwe

22
@ डैकवे, मैं यहां पहुंच गया क्योंकि मैंने ठीक उसी तरह से बचने के लिए रास्ता ढूंढना शुरू कर दिया था! एक वस्तु जो कार्य करती है, एक ही समय में, एक कुंजी और संबंधित मूल्य दोनों बिल्कुल एक सेट के बारे में क्या होना चाहिए। मेरे मामले में, मैं कुंजी (स्ट्रिंग) द्वारा एक सेट से कुछ जटिल वस्तु प्राप्त करना चाहूंगा। इस स्ट्रिंग को मैप किया जा रहा ऑब्जेक्ट के लिए समझाया (और अद्वितीय) है। वास्तव में, पूरी वस्तु उक्त कुंजी के चारों ओर घूमती है। इसके अलावा, फोन करने वाले ने कहा कि स्ट्रिंग, लेकिन वस्तु ही नहीं जानता है; यही कारण है कि यह कुंजी द्वारा इसे पुनः प्राप्त करना चाहता है। मैं अब बेशक एक मानचित्र का उपयोग कर रहा हूं, लेकिन यह अजीब व्यवहार है।
पौलसूरी

4
@KyleM मैं उपयोग के मामले को समझता हूं, लेकिन मैं उन विशेषताओं को न छूने के महत्व पर जोर देना चाहता हूं जो हैशकोड / बराबर का हिस्सा हैं। सेट Javadoc से: "ध्यान दें: यदि परस्पर वस्तुओं को सेट तत्वों के रूप में उपयोग किया जाता है, तो महान देखभाल का उपयोग किया जाना चाहिए। सेट का व्यवहार निर्दिष्ट नहीं है यदि किसी वस्तु का मूल्य इस तरह से बदल दिया जाता है जो वस्तु की तुलना करते हुए समानताओं को प्रभावित करता है। सेट में तत्व। " - मैं उन वस्तुओं को अपरिवर्तनीय होने की सलाह देता हूं, या कम से कम अपरिवर्तनीय प्रमुख विशेषताएं हैं।
स्टिवलो

5
मैं मानता हूं कि आप Map<Foo, Foo>एक प्रतिस्थापन के रूप में उपयोग कर सकते हैं , नकारात्मक पक्ष यह है कि एक मानचित्र को हमेशा कम से कम एक कुंजी और एक मूल्य (और प्रदर्शन के लिए इसे भी हैश को स्टोर करना चाहिए), जबकि एक सेट दूर हो सकता है केवल मूल्य संग्रहीत कर रहा है (और शायद प्रदर्शन के लिए हैश)। तो एक अच्छा सेट कार्यान्वयन समान रूप से तेज़ हो सकता है Map<Foo, Foo>लेकिन 50% तक कम मेमोरी का उपयोग कर सकता है । जावा के मामले में यह मायने नहीं रखेगा, क्योंकि हाशसेट आंतरिक रूप से वैसे भी हाशप पर आधारित है।
मकी

372

सटीक प्रश्न का उत्तर देने के लिए " एक तत्व प्राप्त करने के लिए एक ऑपरेशन क्यों नहीं Setप्रदान करता है जो किसी अन्य तत्व के बराबर होता है?", उत्तर होगा: क्योंकि संग्रह ढांचे के डिजाइनर बहुत आगे की ओर नहीं देख रहे थे। वे आपके बहुत वैध उपयोग के मामले का अनुमान नहीं लगाते थे, भोले ने "गणितीय सेट अमूर्त मॉडल" (जावदोक से) मॉडल करने की कोशिश की और बस उपयोगी get()विधि जोड़ना भूल गए ।

अब निहित प्रश्न " आप तत्व को कैसे प्राप्त करते हैं": मुझे लगता है कि सबसे अच्छा समाधान ए के Map<E,E>बजाय का उपयोग करना है Set<E>, तत्वों को स्वयं को मैप करना है। उस तरह से, आप "सेट" से एक तत्व को कुशलता से प्राप्त कर सकते हैं , क्योंकि Mapएक कुशल हैश टेबल या ट्री एल्गोरिथ्म का उपयोग करके वसीयत की प्राप्त () विधि तत्व को खोज लेगी। यदि आप चाहते हैं, तो आप अपने स्वयं के कार्यान्वयन को लिख सकते हैं Set, अतिरिक्त get()विधि प्रदान करता है , इनकैप्सुलेटिंग Map

निम्नलिखित उत्तर मेरी राय में बुरे या गलत हैं:

"आपको तत्व प्राप्त करने की आवश्यकता नहीं है, क्योंकि आपके पास पहले से ही एक समान वस्तु है": दावा गलत है, जैसा कि आपने पहले ही प्रश्न में दिखाया है। दो वस्तुएं जो समान हैं, उनमें भिन्न स्थिति हो सकती है जो वस्तु समानता के लिए प्रासंगिक नहीं है। लक्ष्य में निहित तत्व की इस स्थिति तक पहुंच प्राप्त करना है Set, न कि "क्वेरी" के रूप में उपयोग की गई वस्तु की स्थिति।

"आपके पास itter का उपयोग करने के अलावा और कोई विकल्प नहीं है": यह एक संग्रह पर एक रेखीय खोज है जो बड़े सेटों के लिए पूरी तरह से अक्षम है (विडंबना यह है कि आंतरिक Setरूप से इसे हैश मैप या पेड़ के रूप में आयोजित किया जाता है जिसे कुशलता से क्वेर किया जा सकता है)। यह मत करो! मैंने उस दृष्टिकोण का उपयोग करके वास्तविक जीवन प्रणालियों में गंभीर प्रदर्शन समस्याओं को देखा है। मेरी राय में, लापता get()विधि के बारे में जो भयानक है वह इतना अधिक नहीं है कि उसके चारों ओर काम करना थोड़ा बोझिल हो, लेकिन यह कि अधिकांश प्रोग्रामर निहितार्थों के बारे में सोचे बिना रैखिक खोज दृष्टिकोण का उपयोग करेंगे।


27
हुंह। बराबरी के कार्यान्वयन को ओवरराइड करना ताकि गैर-बराबर वस्तुएं "बराबर" हो यहां समस्या है। एक विधि के लिए पूछना जो कहती है कि "मुझे इस वस्तु के समान वस्तु प्राप्त हो", और फिर उम्मीद की जाती है कि गैर-समान वस्तु वापस लौटा दी जाए और रखरखाव समस्याओं का कारण बनने में आसान लगता है। जैसा कि दूसरों ने सुझाव दिया है, एक मानचित्र का उपयोग करने से इन सभी समस्याओं का समाधान होता है: और यह वह बनाता है जो आप स्वयं व्याख्यात्मक कर रहे हैं। यह समझना आसान है कि दो गैर-बराबर वस्तुओं के नक्शे में एक ही कुंजी हो सकती है, और एक ही कुंजी होने से उनके बीच संबंध दिखाई देंगे।
डेविड ऑगरन

20
ज़ोरदार शब्द, @ डेविड ऑग्रेन। मेह? पागल? लेकिन आपकी टिप्पणी में, आप "समान" और "समान" शब्दों का उपयोग कर रहे हैं जैसे कि उनका मतलब वही था। वे नहीं। विशेष रूप से, जावा में, पहचान "==" ऑपरेटर द्वारा व्यक्त की जाती है और समानता () विधि द्वारा समानता व्यक्त की जाती है। यदि वे एक ही बात का मतलब है, वहाँ एक बराबर () विधि के लिए की आवश्यकता नहीं होगी। अन्य भाषाओं में, यह निश्चित रूप से अलग हो सकता है। उदाहरण के लिए, ग्रूवी में, पहचान एक () विधि है, और समानता "==" है। अजीब बात है, है ना?
jschreiner

15
जब मैं समान शब्द का उपयोग करना चाहिए था, तब समान शब्द के मेरे उपयोग की आपकी आलोचना बहुत मान्य है। लेकिन एक वस्तु पर बराबरी को परिभाषित करना ताकि फू और बार "बराबर" हैं, लेकिन उनके लिए "समान रूप से पर्याप्त" नहीं हैं उन्हें समान रूप से उपयोग करने के लिए कार्यक्षमता और पठनीयता / स्थिरता दोनों के साथ सभी प्रकार की समस्याएं पैदा करने जा रहा है। संभावित समस्याओं के लिए आइसबर्ग के सेट के साथ यह मुद्दा। उदाहरण के लिए, समान ऑब्जेक्ट में समान हैश कोड होना चाहिए। तो वह संभावित हैश टकराव होने जा रहा है। क्या यह विशेष रूप से foo के अलावा कुछ पाने के लिए .get (foo) कॉल करने के लिए पागल है?
डेविड ऑग्रेन

12
यह शायद ध्यान देने योग्य है कि, जैसे, हैशसेट को हैशपॉप के चारों ओर एक आवरण के रूप में लागू किया जाता है (जो कि डमी मूल्य के लिए कुंजी मैप करता है)। इसलिए, हैशसेट के बजाय स्पष्ट रूप से एक हैशपॉट का उपयोग करने से मेमोरी उपयोग में ओवरहेड का कारण नहीं होगा।
एलेक्सी बी।

4
@ user686249 मुझे लगता है कि यह सिर्फ एक अकादमिक बहस में बदल गया है। मैं मानता हूं कि मैं बराबरी पर रहने पर आपत्ति जताने में नाकामयाब रहा हूं। खासतौर पर आपके जैसे उपयोग में। लेकिन, मुझे इस पद्धति को कॉल करने के विचार पर अभी भी आपत्ति है get()। आपके उदाहरण में, मैं customerSet.get (thisCustomer) द्वारा बहुत भ्रमित होऊंगा। (जबकि, एक मानचित्र, जैसा कि कई उत्तरों द्वारा सुझाया गया है) कैनोनिकलकस्टमरपार्ट.गेट (इस ग्राहक) के साथ ठीक होगा। मैं एक ऐसी विधि के साथ भी ठीक हो जाऊंगा जिसे अधिक स्पष्ट रूप से नाम दिया गया है (जैसे कि NSSet पर उद्देश्य-सी की सदस्य विधि)।
डेविड ऑग्रेन

19

यदि आपके पास एक समान वस्तु है, तो आपको सेट से एक की आवश्यकता क्यों है? यदि यह केवल एक कुंजी द्वारा "बराबर" है, Mapतो एक बेहतर विकल्प होगा।

वैसे भी, निम्नलिखित यह करेंगे:

Foo getEqual(Foo sample, Set<Foo> all) {
  for (Foo one : all) {
    if (one.equals(sample)) {
      return one;
    }
  } 
  return null;
}

Java 8 के साथ यह एक लाइनर बन सकता है:

return all.stream().filter(sample::equals).findAny().orElse(null);

मुझे यह उत्तर बेहतर लगता है, मैं सिर्फ दो रिटर्न स्टेटमेंट का उपयोग करने से बचूंगा, क्योंकि यह ओओपी के खिलाफ है और यह साइक्लोमैटिक कॉम्प्लेक्स मूल्य को अधिक बनाता है।
सिंह

8
@ धन्यवाद, लेकिन एकल निकास प्रतिमान OOP के खिलाफ नहीं है और ज्यादातर फोरट्रान या COBOL की तुलना में अधिक आधुनिक भाषाओं के लिए अमान्य है, यह भी देखें सॉफ्टवेयरइन्जिनियरिंग.स्टैकएक्सचेंज.
Arme Burmeister

1
सेट के बजाय मैप का उपयोग करना एक बेहतर विकल्प की तरह प्रतीत होता है: किसी सेट के तत्वों पर पुनरावृत्ति करना मैप से एकल मान प्राप्त करने की तुलना में अधिक काम करता है। (ओ (एन) बनाम ओ (1))
जेमी फ्लोरनॉय

@JamieFlournoy सही है, अगर आपको कई बार अलग-अलग तत्वों के लिए एक ही सेट की जाँच करनी है तो यह बहुत बेहतर है। एकल उपयोग के लिए नहीं, क्योंकि इसके लिए पहले मानचित्र बनाने के लिए अधिक प्रयास की आवश्यकता होती है।
Arne Burmeister

18

सूची में सेट करें, और फिर getसूची की विधि का उपयोग करें

Set<Foo> set = ...;
List<Foo> list = new ArrayList<Foo>(set);
Foo obj = list.get(0);

37
मुझे यह नहीं मिलता। यह सेट की एक मनमानी वस्तु को पुनः प्राप्त करेगा । नहीं वस्तु।
Aioobe

14

जावा में डिफ़ॉल्ट सेट, दुर्भाग्य से, एक "प्राप्त" ऑपरेशन प्रदान करने के लिए डिज़ाइन नहीं किया गया है, क्योंकि jschreiner सटीक रूप से समझाया गया है।

ब्याज के तत्व को खोजने के लिए ( dacwe द्वारा सुझाए गए ) तत्व को खोजने के लिए या तत्व को हटाने के लिए इसे फिर से जोड़ना और इसे अपडेट किए गए ( केलीएम द्वारा सुझाए गए ) के साथ फिर से जोड़ना , समाधान काम कर सकता है, लेकिन बहुत अक्षम हो सकता है।

समान के कार्यान्वयन को ओवरराइड करना ताकि गैर-बराबर ऑब्जेक्ट "बराबर" हों, जैसा कि डेविड ऑग्रेन द्वारा सही ढंग से कहा गया है , आसानी से रखरखाव की समस्याओं को दूर कर सकता है।

और मैप को एक स्पष्ट प्रतिस्थापन के रूप में उपयोग करना (जैसा कि कई लोगों द्वारा सुझाया गया है), इम्हो, कोड को कम सुरुचिपूर्ण बनाता है।

यदि लक्ष्य सेट में निहित तत्व के मूल उदाहरण तक पहुंच प्राप्त करना है (आशा है कि मैं आपके उपयोग के मामले को सही ढंग से समझ गया था), तो यहां एक और संभावित समाधान है।


जावा के साथ क्लाइंट-सर्वर वीडियोगेम विकसित करते समय मुझे व्यक्तिगत रूप से आपकी समान आवश्यकता थी। मेरे मामले में, प्रत्येक क्लाइंट के पास सर्वर में संग्रहीत घटकों की प्रतियां थीं और समस्या यह थी कि जब भी क्लाइंट को सर्वर की एक वस्तु को संशोधित करने की आवश्यकता होती है।

इंटरनेट के माध्यम से किसी वस्तु को पास करने का मतलब है कि ग्राहक के पास उस वस्तु के विभिन्न उदाहरण हैं। मूल के साथ इस "कॉपी" उदाहरण से मेल खाने के लिए, मैंने जावा यूयूआईडी का उपयोग करने का फैसला किया।

इसलिए मैंने एक सार वर्ग UniqueItem बनाया, जो स्वचालित रूप से अपने उपवर्गों के प्रत्येक उदाहरण के लिए एक यादृच्छिक अद्वितीय आईडी देता है।

यह यूयूआईडी क्लाइंट और सर्वर इंस्टेंस के बीच साझा किया जाता है, इसलिए इस तरह से उन्हें केवल एक मैप का उपयोग करके मैच करना आसान हो सकता है।

हालाँकि सीधे एक समान usecase में एक मानचित्र का उपयोग करना अभी भी असंगत था। कोई यह तर्क दे सकता है कि मैप का उपयोग करना मंटेन और हैंडल के लिए अधिक जटिल हो सकता है।

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

https://github.com/ricpacca/magicset


मूल Java HashSet की तरह, एक MagicHashSet (जो लाइब्रेरी में उपलब्ध MagicSet के कार्यान्वयन में से एक है) एक बैकिंग HashMap का उपयोग करता है, लेकिन इसमें कुंजी के रूप में तत्व और मान के रूप में एक डमी मूल्य होने के बजाय, यह कुंजी के रूप में तत्व के UUID का उपयोग करता है और तत्व ही मूल्य के रूप में। यह सामान्य हैशसेट की तुलना में मेमोरी उपयोग में ओवरहेड का कारण नहीं बनता है।

इसके अलावा, एक मैजिकसेट का उपयोग बिल्कुल सेट के रूप में किया जा सकता है, लेकिन अतिरिक्त कार्यक्षमता प्रदान करने वाले कुछ और तरीकों के साथ, जैसे getFromId (), popFromId (), removeFromId (), आदि।

इसका उपयोग करने की एकमात्र आवश्यकता यह है कि किसी भी तत्व जिसे आप मैजिकसेट में संग्रहित करना चाहते हैं, उसे अमूर्त वर्ग यूनीक इटेम का विस्तार करने की आवश्यकता है।


यहां एक कोड उदाहरण है, एक मैजिकसेट से किसी शहर के मूल उदाहरण को पुनः प्राप्त करने की कल्पना करते हुए, उसी UUID के साथ उस शहर का एक और उदाहरण (या यहां तक ​​कि सिर्फ उसका UUID) दिया गया।

class City extends UniqueItem {

    // Somewhere in this class

    public void doSomething() {
        // Whatever
    }
}

public class GameMap {
    private MagicSet<City> cities;

    public GameMap(Collection<City> cities) {
        cities = new MagicHashSet<>(cities);
    }

    /*
     * cityId is the UUID of the city you want to retrieve.
     * If you have a copied instance of that city, you can simply 
     * call copiedCity.getId() and pass the return value to this method.
     */
    public void doSomethingInCity(UUID cityId) {
        City city = cities.getFromId(cityId);
        city.doSomething();
    }

    // Other methods can be called on a MagicSet too
}

11

यदि आपका सेट वास्तव में NavigableSet<Foo>(जैसे TreeSet) है, और Foo implements Comparable<Foo>, आप उपयोग कर सकते हैं

Foo bar = set.floor(foo); // or .ceiling
if (foo.equals(bar)) {
    // use bar…
}

(संकेत के लिए @ eliran-malka की टिप्पणी के लिए धन्यवाद।)


5
अगर मुझे कोई आपत्ति नहीं है कि मेरे कोड को पढ़ने वाले शुरुआती सोचा कि मैं पूरी तरह से पागल हो गया हूं, तो यह एक महान समाधान होगा।
एडम

10

जावा 8 के साथ आप कर सकते हैं:

Foo foo = set.stream().filter(item->item.equals(theItemYouAreLookingFor)).findFirst().get();

लेकिन सावधान रहें, .get () एक NoSuchElementException को फेंकता है, या आप एक वैकल्पिक आइटम को हेरफेर कर सकते हैं।


5
item->item.equals(theItemYouAreLookingFor)को छोटा किया जा सकता हैtheItemYouAreLookingFor::equals
हेन्नो वर्म्यूलेन

5
Object objectToGet = ...
Map<Object, Object> map = new HashMap<Object, Object>(set.size());
for (Object o : set) {
    map.put(o, o);
}
Object objectFromSet = map.get(objectToGet);

यदि आप केवल एक प्राप्त करते हैं तो यह बहुत अच्छा प्रदर्शन नहीं होगा क्योंकि आप अपने सभी तत्वों पर लूप करेंगे, लेकिन जब एक बड़े सेट पर कई पुनः प्राप्त करते हैं तो आपको अंतर दिखाई देगा।


5

क्यों:

ऐसा लगता है कि सेट तुलना के साधन प्रदान करने में एक उपयोगी भूमिका निभाता है। इसे डुप्लिकेट तत्वों को संग्रहीत नहीं करने के लिए डिज़ाइन किया गया है।

इस आशय / डिजाइन के कारण, यदि किसी को संग्रहित वस्तु का संदर्भ प्राप्त करना है, तो उसे म्यूट कर दें, यह संभव है कि सेट के डिजाइन इरादों को विफल किया जा सकता है और अप्रत्याशित व्यवहार का कारण बन सकता है।

से javadocs

महान देखभाल का प्रयोग करना चाहिए यदि उत्परिवर्तित वस्तुओं को निर्धारित तत्वों के रूप में उपयोग किया जाता है। एक सेट का व्यवहार निर्दिष्ट नहीं है अगर किसी ऑब्जेक्ट का मूल्य इस तरह से बदल दिया जाता है जो समान तुलना को प्रभावित करता है जबकि ऑब्जेक्ट सेट में एक तत्व है।

किस तरह:

अब जब धाराओं को पेश किया गया है तो निम्न कार्य कर सकते हैं

mySet.stream()
.filter(object -> object.property.equals(myProperty))
.findFirst().get();

2

Arrays वर्ग का उपयोग करने के बारे में क्या?

import java.util.Arrays;
import java.util.List;
import java.util.HashSet;
import java.util.Arrays;

public class MyClass {
    public static void main(String args[]) {
        Set mySet = new HashSet();
        mySet.add("one");
        mySet.add("two");
        List list = Arrays.asList(mySet.toArray());
        Object o0 = list.get(0);
        Object o1 = list.get(1);
        System.out.println("items " + o0+","+o1);
    }
}

आउटपुट:
आइटम एक, दो



1

मुझे पता है, यह बहुत पहले से पूछा और उत्तर दिया गया है, हालांकि अगर किसी को दिलचस्पी है, तो यहां मेरा समाधान है - कस्टम सेट क्लास हैशबॉल द्वारा समर्थित है:

http://pastebin.com/Qv6S91n9

आप आसानी से अन्य सभी सेट विधियों को लागू कर सकते हैं।


7
केवल एक को जोड़ने के बजाय उदाहरण को शामिल करना पसंद किया जाता है।
सभी कार्यकर्ता आवश्यक

1

वहाँ किया गया था कि!! यदि आप अमरूद को नक्शे में बदलने का त्वरित तरीका इस्तेमाल कर रहे हैं:

Map<Integer,Foo> map = Maps.uniqueIndex(fooSet, Foo::getKey);

1

आप Iterator वर्ग का उपयोग कर सकते हैं

import java.util.Iterator;
import java.util.HashSet;

public class MyClass {
 public static void main(String[ ] args) {
 HashSet<String> animals = new HashSet<String>();
animals.add("fox");
animals.add("cat");
animals.add("dog");
animals.add("rabbit");

Iterator<String> it = animals.iterator();
while(it.hasNext()) {
  String value = it.next();
  System.out.println(value);   
 }
 }
}

1

यदि आप HashSet से nth Element चाहते हैं, तो आप नीचे दिए गए समाधान के साथ जा सकते हैं, यहाँ मैंने HashSet में ModelClass का ऑब्जेक्ट जोड़ा है।

ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
    m1 = (ModelClass) itr.next();
    if(nth == index) {
        System.out.println(m1);
        break;
    }
}

1

यदि आप के कार्यान्वयन की पहली कुछ पंक्तियों java.util.HashSetको देखेंगे तो आप देखेंगे:

public class HashSet<E>
    ....
    private transient HashMap<E,Object> map;

तो किसी भी तरह से अंतरिम रूप से HashSetउपयोग करता HashMapहै, जिसका अर्थ है कि यदि आप बस HashMapसीधे उपयोग करते हैं और कुंजी और मूल्य के समान उपयोग करते हैं, तो आपको वह प्रभाव मिलेगा जो आप चाहते हैं और अपने आप को कुछ मेमोरी बचा सकते हैं।


1

यह उपयोग करने के लिए उचित वस्तु की तरह लग रहा है अमरूद से आंतरिक है:

अन्य अपरिवर्तनीय प्रकारों के लिए String.intern () के समतुल्य व्यवहार प्रदान करता है। आम कार्यान्वयन इंटरनर्स वर्ग से उपलब्ध हैं ।

इसमें कुछ बहुत ही रोचक लीवर भी हैं, जैसे कि संगामिलि लिवेल, या उपयोग किए जाने वाले संदर्भों के प्रकार (यह ध्यान देने योग्य हो सकता है कि यह एक सॉफ्टइंटरटेनर प्रदान नहीं करता है जिसे मैं एक WeakInterner की तुलना में अधिक उपयोगी देख सकता हूं)।


0

क्योंकि सेट का कोई विशेष कार्यान्वयन यादृच्छिक अभिगम हो सकता है या नहीं भी हो सकता है ।

समान तत्व मिलने के बाद, आप पुन: परिणाम प्राप्त करने के लिए पुनरावृत्तियों की विधि का उपयोग करके, आप सेट के माध्यम से एक पुनरावृत्ति और चरण प्राप्त कर सकते हैं next()। यह कार्यान्वयन की परवाह किए बिना काम करता है। यदि कार्यान्वयन रैंडम एक्सेस नहीं है (चित्र में लिस्ट-लिस्टेड सेट सेट है), get(E element)इंटरफ़ेस में एक विधि भ्रामक होगा, क्योंकि उसे वापस जाने के लिए तत्व को खोजने के लिए संग्रह को पुनरावृत्त get(E element)करना होगा , और इसका मतलब यह होगा कि यह होगा आवश्यक है, कि सेट सीधे तत्व को प्राप्त करने के लिए कूद सकता है।

contains() कार्यान्वयन के आधार पर, निश्चित रूप से एक ही काम करना पड़ सकता है या नहीं हो सकता है, लेकिन नाम उसी तरह की गलतफहमी के लिए उधार देने के लिए प्रतीत नहीं होता है।


2
कुछ भी प्राप्त () विधि पहले से ही () विधि द्वारा किया जा रहा है। आप सम्‍मिलित ऑब्जेक्ट को प्राप्त किए बिना () और उसके (।) विधि को कॉल किए बिना लागू नहीं कर सकते। लग रहा था कि एपीआई डिजाइनरों को java.util में एक जोड़ () जोड़ने के बारे में कोई गुण नहीं था। हालांकि यह कुछ कार्यान्वयन में धीमा होगा।
ब्रायन रिंक

मुझे नहीं लगता कि यह सच है। दो वस्तुओं को बराबर के माध्यम से बराबर किया जा सकता है, लेकिन == के माध्यम से समान नहीं है। यदि आपके पास ऑब्जेक्ट A, और सेट S में ऑब्जेक्ट B, और A.equals (B) है, लेकिन A! = B है और आप B का संदर्भ प्राप्त करना चाहते हैं, तो आप S.get (A) को संदर्भ प्राप्त करने के लिए कॉल कर सकते हैं। B, यह मानते हुए कि आपके पास सूची की विधि के शब्दार्थ के साथ एक विधि है, जो कि जाँच से अलग उपयोग मामला है यदि S.contains (A) (जो यह होगा)। यह संग्रह के लिए दुर्लभ उपयोग का मामला भी नहीं है।
बजे टॉम ट्रान्सस्की

0

हां, का उपयोग करें HashMap... लेकिन एक विशेष तरीके से: HashMapएक छद्म के रूप में उपयोग करने की कोशिश में मैं फँस गया- Setक्या "वास्तविक" तत्वों Map/Setऔर "उम्मीदवार" तत्वों के बीच संभावित भ्रम है , अर्थात तत्वों का परीक्षण किया जाता है कि क्या एक equalतत्व पहले से मौजूद है। यह मूर्खता से दूर है, लेकिन आपको जाल से दूर करता है:

class SelfMappingHashMap<V> extends HashMap<V, V>{
    @Override
    public String toString(){
        // otherwise you get lots of "... object1=object1, object2=object2..." stuff
        return keySet().toString();
    }

    @Override
    public V get( Object key ){
        throw new UnsupportedOperationException( "use tryToGetRealFromCandidate()");
    }

    @Override
    public V put( V key, V value ){
       // thorny issue here: if you were indavertently to `put`
       // a "candidate instance" with the element already in the `Map/Set`: 
       // these will obviously be considered equivalent 
       assert key.equals( value );
       return super.put( key, value );
    }

    public V tryToGetRealFromCandidate( V key ){
        return super.get(key);
    }
}

फिर ऐसा करें:

SelfMappingHashMap<SomeClass> selfMap = new SelfMappingHashMap<SomeClass>();
...
SomeClass candidate = new SomeClass();
if( selfMap.contains( candidate ) ){
    SomeClass realThing = selfMap.tryToGetRealFromCandidate( candidate );
    ...
    realThing.useInSomeWay()...
}

लेकिन ... अब आप candidateकिसी भी तरह से आत्म-विनाश करना चाहते हैं जब तक कि प्रोग्रामर वास्तव में तुरंत इसे नहीं डालता है Map/Set... आप इसे contains"टेंट" करना चाहते हैं candidateताकि इसका कोई भी उपयोग तब तक न हो जब तक कि यह Mapइसे "अनाथमा" में शामिल न कर दे। "। शायद आप SomeClassएक नया Taintableइंटरफ़ेस लागू कर सकते हैं ।

नीचे के रूप में एक अधिक संतोषजनक समाधान गेटटेबसेट है । हालाँकि, इसके लिए आपको काम करने के लिए या तो SomeClassसभी रचनाकारों को गैर-दृश्यमान बनाने के लिए (या ... सक्षम और इसके लिए एक आवरण वर्ग का उपयोग करने के लिए तैयार) करने के लिए डिजाइन का प्रभारी होना चाहिए :

public interface NoVisibleConstructor {
    // again, this is a "nudge" technique, in the sense that there is no known method of 
    // making an interface enforce "no visible constructor" in its implementing classes 
    // - of course when Java finally implements full multiple inheritance some reflection 
    // technique might be used...
    NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet );
};

public interface GettableSet<V extends NoVisibleConstructor> extends Set<V> {
    V getGenuineFromImpostor( V impostor ); // see below for naming
}

कार्यान्वयन:

public class GettableHashSet<V extends NoVisibleConstructor> implements GettableSet<V> {
    private Map<V, V> map = new HashMap<V, V>();

    @Override
    public V getGenuineFromImpostor(V impostor ) {
        return map.get( impostor );
    }

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean contains(Object o) {
        return map.containsKey( o );
    }

    @Override
    public boolean add(V e) {
        assert e != null;
        V result = map.put( e,  e );
        return result != null;
    }

    @Override
    public boolean remove(Object o) {
        V result = map.remove( o );
        return result != null;
    }

    @Override
    public boolean addAll(Collection<? extends V> c) {
        // for example:
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        map.clear();
    }

    // implement the other methods from Set ...
}

आपकी NoVisibleConstructorकक्षाएं तब इस तरह दिखती हैं:

class SomeClass implements NoVisibleConstructor {

    private SomeClass( Object param1, Object param2 ){
        // ...
    }

    static SomeClass getOrCreate( GettableSet<SomeClass> gettableSet, Object param1, Object param2 ) {
        SomeClass candidate = new SomeClass( param1, param2 );
        if (gettableSet.contains(candidate)) {
            // obviously this then means that the candidate "fails" (or is revealed
            // to be an "impostor" if you will).  Return the existing element:
            return gettableSet.getGenuineFromImpostor(candidate);
        }
        gettableSet.add( candidate );
        return candidate;
    }

    @Override
    public NoVisibleConstructor addOrGetExisting( GettableSet<? extends NoVisibleConstructor> gettableSet ){
       // more elegant implementation-hiding: see below
    }
}

ऐसी NoVisibleConstructorकक्षा के साथ PS एक तकनीकी समस्या : यह आपत्ति हो सकती है कि ऐसा वर्ग स्वाभाविक है final, जो अवांछनीय हो सकता है। वास्तव में आप हमेशा एक डमी पैरामीटर रहित protectedनिर्माता जोड़ सकते हैं :

protected SomeClass(){
    throw new UnsupportedOperationException();
}

... जो कम से कम एक उपवर्ग को संकलित करने देता। फिर आपको इस बारे में सोचना होगा कि क्या आपको getOrCreate()उप-कारखाने में एक और कारखाना विधि शामिल करने की आवश्यकता है ।

अंतिम चरण आपके सेट सदस्यों के लिए एक सूची के लिए एक सार आधार वर्ग (NB "तत्व", एक सेट के लिए "सदस्य") है (जब संभव हो - फिर से, एक आवरण वर्ग का उपयोग करने के लिए गुंजाइश जहां वर्ग आपके नियंत्रण में नहीं है, या पहले से ही एक बेस क्लास, आदि), अधिकतम कार्यान्वयन-छुपा के लिए:

public abstract class AbstractSetMember implements NoVisibleConstructor {
    @Override
    public NoVisibleConstructor
            addOrGetExisting(GettableSet<? extends NoVisibleConstructor> gettableSet) {
        AbstractSetMember member = this;
        @SuppressWarnings("unchecked") // unavoidable!
        GettableSet<AbstractSetMembers> set = (GettableSet<AbstractSetMember>) gettableSet;
        if (gettableSet.contains( member )) {
            member = set.getGenuineFromImpostor( member );
            cleanUpAfterFindingGenuine( set );
        } else {
            addNewToSet( set );
        }
        return member;
    }

    abstract public void addNewToSet(GettableSet<? extends AbstractSetMember> gettableSet );
    abstract public void cleanUpAfterFindingGenuine(GettableSet<? extends AbstractSetMember> gettableSet );
}

... उपयोग काफी स्पष्ट है (अपने अंदर SomeClassके staticकारखाने विधि):

SomeClass setMember = new SomeClass( param1, param2 ).addOrGetExisting( set );

0

हैश कोड का अनुबंध स्पष्ट करता है कि:

"यदि ऑब्जेक्ट ऑब्जेक्ट के अनुसार दो ऑब्जेक्ट समान हैं, तो दो ऑब्जेक्ट्स में से प्रत्येक पर हैशकोड विधि को कॉल करना एक ही पूर्णांक परिणाम का उत्पादन करना होगा।"

तो आपकी धारणा:

"स्पष्ट करने के लिए, बराबरी की विधि को ओवरराइड किया जाता है, लेकिन यह केवल एक फ़ील्ड की जांच करता है, सभी नहीं। इसलिए दो Foo ऑब्जेक्ट्स जिन्हें समान माना जाता है, वास्तव में अलग-अलग मूल्य हो सकते हैं, इसीलिए मैं सिर्फ foo का उपयोग नहीं कर सकता।"

गलत है और आप अनुबंध तोड़ रहे हैं। यदि हम सेट इंटरफ़ेस की "समाहित" विधि को देखते हैं, तो हमारे पास यह है:

बूलियन होता है (ऑब्जेक्ट ओ);
यह सेट निर्दिष्ट तत्व शामिल है, तो सही है। अधिक औपचारिक रूप से, यदि केवल इस सेट में एक तत्व "e" है, जो o == अशक्त है, तो सही है? e == नल: o.equals (e)

आप जो चाहते हैं उसे पूरा करने के लिए, आप एक मानचित्र का उपयोग कर सकते हैं जहां आप कुंजी को परिभाषित करते हैं और अपने तत्व को उस कुंजी के साथ संग्रहीत करते हैं जो परिभाषित करता है कि ऑब्जेक्ट एक दूसरे के बराबर या बराबर कैसे हैं।


-2

त्वरित सहायक विधि जो इस स्थिति को संबोधित कर सकती है:

<T> T onlyItem(Collection<T> items) {
    if (items.size() != 1)
        throw new IllegalArgumentException("Collection must have single item; instead it has " + items.size());

    return items.iterator().next();
}

8
यह बहुत अजीब है कि इस उत्तर ने इतने उत्थान प्राप्त किए हैं क्योंकि यह प्रश्न का उत्तर नहीं देता है या किसी भी तरह से इसे संबोधित करने का प्रयास नहीं करता है।
डेविड कॉनरेड

-2

निम्नलिखित एक दृष्टिकोण हो सकता है

   SharedPreferences se_get = getSharedPreferences("points",MODE_PRIVATE);
   Set<String> main = se_get.getStringSet("mydata",null);
   for(int jk = 0 ; jk < main.size();jk++)
   {
      Log.i("data",String.valueOf(main.toArray()[jk]));
   }

-2

किसी सरणी का उपयोग करके देखें:

ObjectClass[] arrayName = SetOfObjects.toArray(new ObjectClass[setOfObjects.size()]);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.