मैं जावा सेट्स को कैसे पुनरावृत्त और संशोधित कर सकता हूं?


80

मान लीजिए कि मेरे पास सेट ऑफ इंटेगर है, और मैं सेट में हर इंटेगर को बढ़ाना चाहता हूं। यह मैं कैसे करूंगा?

क्या मैंने इसे पुनरावृति करते हुए सेट से तत्वों को जोड़ने और हटाने की अनुमति दी है?

क्या मुझे मूल सेट की पुनरावृत्ति करते हुए तत्वों को नया सेट बनाने की आवश्यकता होगी, जिसमें मैं तत्वों को "कॉपी और संशोधित" करूं?

संपादित करें: क्या होगा यदि सेट के तत्व अपरिवर्तनीय हैं?

जवाबों:


92

आप Iterator ऑब्जेक्ट के साथ चलना के दौरान एक सेट से सुरक्षित रूप से निकाल सकते हैं; अपने एपीआई के माध्यम से एक सेट को संशोधित करने का प्रयास करते समय पुनरावृति इट्रेटर को तोड़ देगा। सेट वर्ग getIterator () के माध्यम से एक पुनरावृत्ति प्रदान करता है।

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

Set<Integer> s; //contains your Integers
...
Set<Integer> temp = new Set<Integer>();
for(Integer i : s)
    temp.add(i+1);
s.clear();
s.addAll(temp);

1
क्या कूड़ा उठाने वाले को मूल सेट छोड़ना और नए सेट का उपयोग जारी रखना आसान नहीं होगा? या तो अस्थायी सेट एकत्र हो जाता है या मूल सेट, मेरा और साथ ही अस्थायी सेट रखता है और मूल को बदलने में परेशान नहीं करता है? हालाँकि, मेरे मामले में यह संभव नहीं था क्योंकि मूल सेट अंतिम था, इसलिए मैंने स्वीकार कर लिया।
बटंस .४०

@JonathanWeatherhead क्या आपका मतलब यह था कि दूसरा शब्द होने के cannotबजाय can? जैसे, You cannot safely removeइसके बजाय You can safely remove? उस पहले पैराग्राफ में एक विरोधाभास की तरह लगता है।
बेसिल बोर्क

@BasilBourque मैं नहीं कर सकता 'का मतलब है। डॉक्स स्थिति के रूप में Iterator :: remove () विधि सुरक्षित है। docs.oracle.com/javase/7/docs/api/java/util/Iterator.html
जोनाथन

error: incompatible types: Object cannot be converted to Integer
अल्हलाल

40

यदि आप अपने सेट में तत्वों पर जाने के लिए एक इटेरेटर ऑब्जेक्ट का उपयोग करते हैं, तो आप क्या कर सकते हैं। आप उन्हें चलते-फिरते ठीक कर सकते हैं। हालाँकि उन्हें लूप में रखते समय (या तो "मानक", प्रत्येक प्रकार के लिए) आपको परेशानी में डाल देगा:

Set<Integer> set = new TreeSet<Integer>();
    set.add(1);
    set.add(2);
    set.add(3);

    //good way:
    Iterator<Integer> iterator = set.iterator();
    while(iterator.hasNext()) {
        Integer setElement = iterator.next();
        if(setElement==2) {
            iterator.remove();
        }
    }

    //bad way:
    for(Integer setElement:set) {
        if(setElement==2) {
            //might work or might throw exception, Java calls it indefined behaviour:
            set.remove(setElement);
        } 
    }

@ मृग्लोम की टिप्पणी के अनुसार, यहां अधिक विवरण दिए गए हैं कि "खराब" तरीका ऊपर वर्णित क्यों है, अच्छी तरह से ... बुरा:

जावा उच्च स्तर पर इसे कैसे लागू करता है, इस बारे में बहुत अधिक जानकारी प्राप्त किए बिना, हम कह सकते हैं कि "खराब" तरीका खराब है क्योंकि यह जावा डॉक्स में स्पष्ट रूप से निर्धारित है:

https://docs.oracle.com/javase/8/docs/api/java/util/ConcurrentModificationException.html

दूसरों के बीच में, (जोर मेरा):

" उदाहरण के लिए, आम तौर पर एक संग्रह को संशोधित करने के लिए एक धागे के लिए यह स्वीकार्य नहीं है, जबकि एक और धागा उस पर पुनरावृत्त होता है। सामान्य तौर पर, इन परिस्थितियों में पुनरावृत्ति के परिणाम अपरिभाषित होते हैं। कुछ Iterator कार्यान्वयन (सामान्य प्रयोजन संग्रह के सभी सहित) JRE द्वारा प्रदान किए गए कार्यान्वयन) इस अपवाद को फेंकना चुन सकते हैं यदि इस व्यवहार का पता चला है "(...)

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

अधिक विवरणों में जाने के लिए: एक वस्तु जिसे फॉरएप लूप में इस्तेमाल किया जा सकता है, उसे "java.lang.Iterable" इंटरफ़ेस ( यहां javadoc ) को लागू करने की आवश्यकता है । यह एक Iterator (इस इंटरफ़ेस में पाया गया "Iterator" विधि के माध्यम से) पैदा करता है , जो कि मांग पर तुरंत दिया जाता है, और आंतरिक रूप से Iterable ऑब्जेक्ट का संदर्भ होगा जिसमें से इसे बनाया गया था। हालाँकि, जब एक forterach लूप में एक Iterable ऑब्जेक्ट का उपयोग किया जाता है, तो इस पुनरावृत्त का उदाहरण उपयोगकर्ता के लिए छिपा होता है (आप इसे किसी भी तरह से स्वयं एक्सेस नहीं कर सकते हैं)।

यह इस तथ्य के साथ युग्मित है कि एक Iterator बहुत ही स्टेटफुल है, अर्थात इसका जादू करने के लिए और इसके "अगले" और "hasNext" तरीकों के लिए सुसंगत प्रतिक्रियाएं हैं, इसके लिए यह आवश्यक है कि बैकिंग ऑब्जेक्ट को पुनरावृत्ति करने वाले की तुलना में किसी और चीज़ से नहीं बदला जाए। जबकि यह पुनरावृत्ति कर रहा है, इसे बनाता है ताकि यह अपवाद को फेंक दे जैसे ही यह पता चलता है कि बैकिंग ऑब्जेक्ट में कुछ बदल गया है, जबकि यह इसके बारे में पुनरावृत्ति कर रहा है।

जावा इस "फेल-फास्ट" पुनरावृत्ति को कहता है: यानी कुछ क्रियाएं हैं, आमतौर पर वे जो एक Iterable उदाहरण को संशोधित करते हैं (जबकि एक Iterator इस पर पुनरावृत्ति कर रहा है)। "फेल-फास्ट" धारणा का "असफल" हिस्सा एक आईटर की क्षमता को संदर्भित करता है ताकि यह पता लगाया जा सके कि इस तरह की "विफल" कार्रवाई कब होती है। "विफल-तेज़" (", जिसे मेरी राय में" सर्वश्रेष्ठ-प्रयास-तेज़ "कहा जाना चाहिए) का" तेज़ "हिस्सा, समवर्तीमॉडिफिकेशन अपवाद के माध्यम से पुनरावृत्ति को समाप्त कर देगा जैसे ही यह पता लगा सकता है कि" विफल "कार्रवाई होता है।


1
क्या आप स्पष्ट कर सकते हैं कि बुरा तरीका असफल क्यों होता है?
मर्ग्लोम

@mrgloom मैंने मूल रूप से अधिक विवरण जोड़े हैं, क्यों, एक समवर्ती परिक्रमण अपवाद को तब भी फेंक दिया जा सकता है जब एक वस्तु पर केवल एक धागा काम कर रहा हो
शिवन ड्रैगन

कुछ मामलों के लिए आपको java.lang.UnsupportedOperationException
Aguid

4

मुझे बहुत अधिक आईटीआर शब्दार्थ पसंद नहीं है, कृपया इसे एक विकल्प के रूप में मानें। यह भी सुरक्षित है क्योंकि आप अपनी आंतरिक स्थिति को कम प्रकाशित करते हैं

private Map<String, String> JSONtoMAP(String jsonString) {

    JSONObject json = new JSONObject(jsonString);
    Map<String, String> outMap = new HashMap<String, String>();

    for (String curKey : (Set<String>) json.keySet()) {
        outMap.put(curKey, json.getString(curKey));
    }

    return outMap;

}

0

आप आदिम int का एक परस्पर आवरण बना सकते हैं और उन का एक सेट बना सकते हैं:

class MutableInteger
{
    private int value;
    public int getValue()
    {
        return value;
    }
    public void setValue(int value)
    {
        this.value = value;
    }
}

class Test
{
    public static void main(String[] args)
    {
        Set<MutableInteger> mySet = new HashSet<MutableInteger>();
        // populate the set
        // ....

        for (MutableInteger integer: mySet)
        {
            integer.setValue(integer.getValue() + 1);
        }
    }
}

बेशक अगर आप हैशसेट का उपयोग कर रहे हैं, तो आपको अपने MutableInteger में हैश को बराबर करना चाहिए, लेकिन वह इस उत्तर के दायरे से बाहर है।


0

सबसे पहले, मेरा मानना ​​है कि एक बार में कई काम करने की कोशिश करना सामान्य तौर पर एक बुरा अभ्यास है और मैं आपको सुझाव देता हूं कि आप जो हासिल करने की कोशिश कर रहे हैं उस पर सोचें।

यह एक अच्छे सैद्धांतिक प्रश्न के रूप में कार्य करता है, हालांकि और इंटरफ़ेस के CopyOnWriteArraySetकार्यान्वयन को इकट्ठा करने से मैं java.util.Setआपके विशेष आवश्यकताओं को पूरा करता है।

http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/CopyOnWriteArraySet.html

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