एक हैशमैप में एक कुंजी दी गई है, एक मूल्य कैसे अपडेट करें?


624

मान लीजिए, हमारे पास HashMap<String, Integer>जावा में है।

मैं स्ट्रिंग के प्रत्येक अस्तित्व के लिए स्ट्रिंग-कुंजी के पूर्णांक-मूल्य (वृद्धि) को कैसे अपडेट (अपडेट) करूं?

कोई भी इस जोड़ी को हटा सकता है और पुन: स्थापित कर सकता है, लेकिन ओवरहेड एक चिंता का विषय होगा।
दूसरा तरीका यह होगा कि आप नई जोड़ी लगाएं और पुराने को बदल दिया जाए।

बाद के मामले में, क्या होता है अगर एक नई कुंजी के साथ हैशकोड टकराव होता है जिसे मैं सम्मिलित करने की कोशिश कर रहा हूं? हैशटेबल के लिए सही व्यवहार इसके लिए एक अलग स्थान निर्दिष्ट करना होगा, या वर्तमान बाल्टी में इसकी सूची बनाना होगा।

जवाबों:


970
map.put(key, map.get(key) + 1);

ठीक होना चाहिए। यह मौजूदा मैपिंग के लिए मान को अपडेट करेगा। ध्यान दें कि यह ऑटो-बॉक्सिंग का उपयोग करता है। map.get(key)हमें इसकी मदद से संबंधित कुंजी का मान मिलता है, फिर आप अपनी आवश्यकता के अनुसार अपडेट कर सकते हैं। यहाँ मैं 1 से वेतन वृद्धि का अद्यतन कर रहा हूँ।


21
वास्तव में यह सबसे मजबूत और स्केलेबल उद्यम समाधान है।
लविर द वायलेट

12
@Lavir, इसका बुरा समाधान नहीं है, लेकिन न ही देखें कि यह कैसे सबसे मजबूत और स्केलेबल है। इसके बजाय एक परमाणु नाशक बहुत अधिक स्केलेबल है।
जॉन विंट

13
यह मानता है कि कुंजी मौजूद है, है ना? मैं nullPointer अपवाद हो रही है जब यह नहीं करता है।
इयान

84
जावा 8 के साथ, इसका उपयोग करके आसानी से बचा जा सकता है getOrDefault, उदाहरण के लिए:map.put(key, count.getOrDefault(key, 0) + 1);
मार्टिन

2
@ मर्टिन .. map.put (कुंजी, map.getOrDefault (कुंजी, 0) + 1)
सथेश

110

जावा 8 रास्ता:

आप computeIfPresentविधि का उपयोग कर सकते हैं और इसे एक मैपिंग फ़ंक्शन की आपूर्ति कर सकते हैं , जिसे मौजूदा के आधार पर एक नए मूल्य की गणना करने के लिए कहा जाएगा।

उदाहरण के लिए,

Map<String, Integer> words = new HashMap<>();
words.put("hello", 3);
words.put("world", 4);
words.computeIfPresent("hello", (k, v) -> v + 1);
System.out.println(words.get("hello"));

वैकल्पिक रूप से, आप mergeविधि का उपयोग कर सकते हैं , जहां 1 डिफ़ॉल्ट मान है और फ़ंक्शन वृद्धि 1 से मौजूदा मूल्य है:

words.merge("hello", 1, Integer::sum);

इसके अलावा, अन्य उपयोगी तरीकों, के रूप में इस तरह के का एक समूह है putIfAbsent, getOrDefault, forEach, आदि


3
मैंने अभी आपके समाधान का परीक्षण किया है। दूसरा एक, विधि संदर्भ के साथ एक, काम करता है। पहले एक, लैम्ब्डा एक्सप्रेशन एक, लगातार काम नहीं कर रहा है जब आपके नक्शे का कोई भी मूल्य null(कहना words.put("hello", null);) है, तो परिणाम अभी भी वैसा nullनहीं है 1जैसा मैं उम्मीद करूंगा।
ताओ झांग

3
Javadoc से: "यदि निर्दिष्ट कुंजी के लिए मान मौजूद है और गैर-शून्य है, तो एक नए मानचित्रण की गणना करने का प्रयास करता है"। आप compute()इसके बजाय उपयोग कर सकते हैं , यह nullमानों को भी संभाल लेगा ।
डमरू

मैं 1 .mergeसे अपने मूल्य में वृद्धि करना चाहता हूं। क्या मेरा समाधान है Integer::sum?
S_K

48
hashmap.put(key, hashmap.get(key) + 1);

यह विधि किसी मौजूदा कुंजी के मान putको बदल देगी और मौजूद नहीं होने पर बनाएगी।


55
नहीं, यह नहीं बनाता है, यह देता है nullPointer Exception
smttsp

13
कोड दिए गए प्रश्न के लिए एक सही उत्तर है, लेकिन स्वीकृत उत्तर में ठीक उसी कोड के पोस्ट किए जाने के एक साल बाद पोस्ट किया गया था। इस उत्तर को अलग करने वाली बात यह कहती है कि यह एक नई प्रविष्टि हो सकती है, जो इस उदाहरण में नहीं है। यदि आप किसी गैर-मौजूद कुंजी / मान के लिए hashmap.get (कुंजी) का उपयोग कर रहे हैं, तो आप शून्य हो जाएंगे और जब आप वेतन वृद्धि का प्रयास करेंगे, जैसा कि @smttsp का कहना है कि यह NPE होगा। -1
जच

8
यह उत्तर गलत है। गैर-मौजूदा कुंजियों के लिए NullPointerException
Eleanore

@smttp NullpointterException केवल तभी यदि आपने मूल्य को प्रारंभ नहीं किया है (जैसा कि आप जानते हैं कि आप वेतन वृद्धि नहीं कर सकते हैं)
मेहदी

डुप्लीकेशन और गलत स्पष्टीकरण ... और अगर यह मौजूद नहीं है तो आप इसे बनाएंगेnull + 1 क्योंकि यह nullइंक्रीमेंट करने के लिए पूर्णांक में अनबॉक्स करने की कोशिश नहीं करेगा ।
एक्सलह

43

सरलीकृत जावा 8 रास्ता:

map.put(key, map.getOrDefault(key, 0) + 1);

यह HashMap की विधि का उपयोग करता है जो एक कुंजी के लिए मान प्राप्त करता है, लेकिन यदि कुंजी को पुनर्प्राप्त नहीं किया जा सकता है तो यह निर्दिष्ट डिफ़ॉल्ट मान (इस मामले में '0') देता है।

यह कोर जावा के भीतर समर्थित है: HashMap <K, V> getOrDefault (ऑब्जेक्ट कुंजी, V defaultValue)


3
यदि आप जावा 1.8 पर हैं तो यह बेहतर है
हेमंत नागपाल

30

Integerद्वारा बदलें AtomicIntegerऔर उस पर incrementAndGet/ getAndIncrementविधियों में से एक को कॉल करें ।

एक विकल्प intअपनी MutableIntegerकक्षा में एक लपेटना है जिसमें एक increment()विधि है, आपके पास अभी तक हल करने के लिए एक थ्रेडसेफ़्टी चिंता है।


37
AtomicInteger एक Mutable Integer है लेकिन बिल्टिन है। मुझे गंभीरता से संदेह है कि आपका अपना MutableInteger लिखना एक बेहतर विचार है।
पीटर लॉरी

कस्टम MutableIntegerबेहतर है, AtomicIntegerउपयोग के रूप में volatile, जिसमें ओवरहेड है। मैं int[1]इसके बजाय का उपयोग करेंगे MutableInteger
ओलिव

@ ऑलिव: समवर्ती नहीं।
बालुसक

@BalusC लेकिन फिर भी, अस्थिर लेखन अधिक महंगा है। यह कैश को अमान्य करता है। यदि यह कोई अंतर नहीं था, तो सभी चर अस्थिर होंगे।
ओलिव

@Oliv: प्रश्न में स्पष्ट रूप से हैशकोड टकराव का उल्लेख है, इसलिए संक्षिप्त रूप ओपी के लिए महत्वपूर्ण है।
बालुस

19

एक पंक्ति समाधान:

map.put(key, map.containsKey(key) ? map.get(key) + 1 : 1);

4
यह मौजूदा जवाब में कुछ नया नहीं जोड़ता है, क्या यह?
रॉबर्ट

1
हाँ यह करता है। यह सही चिह्नित उत्तर NullPointerException को फेंक देगा यदि कुंजी मौजूद नहीं है। यह समाधान ठीक काम करेगा।
हेमंत नागपाल

18

@ मैथ्यू का समाधान सबसे सरल है और ज्यादातर मामलों में पर्याप्त प्रदर्शन करेगा।

यदि आपको उच्च प्रदर्शन की आवश्यकता है, तो AtomicInteger एक बेहतर समाधान है ala @BalusC।

हालाँकि, एक तेज़ समाधान (प्रदान की गई थ्रेड सुरक्षा कोई समस्या नहीं है) TObjectIntHashMap का उपयोग करना है जो एक वृद्धि (कुंजी) विधि प्रदान करता है और AtomicIntegers बनाने की तुलना में आदिम और कम वस्तुओं का उपयोग करता है। जैसे

TObjectIntHashMap<String> map = new TObjectIntHashMap<String>()
map.increment("aaa");

13

आप नीचे की तरह वृद्धि कर सकते हैं लेकिन आपको अस्तित्व की जांच करने की आवश्यकता है ताकि एक NullPointerException न फेंकी जाए

if(!map.containsKey(key)) {
 p.put(key,1);
}
else {
 p.put(key, map.getKey()+1);
}

9

क्या हैश मौजूद है (मान के रूप में 0 के साथ) या क्या इसे पहले वेतन वृद्धि पर नक्शे में "डाल" दिया गया है? यदि यह पहली वेतन वृद्धि पर "लगाया गया" है, तो कोड को इस तरह दिखना चाहिए:

if (hashmap.containsKey(key)) {
    hashmap.put(key, hashmap.get(key)+1);
} else { 
    hashmap.put(key,1);
}

7

थोड़ी देर हो सकती है लेकिन यहाँ मेरे दो सेंट हैं।

यदि आप Java 8 का उपयोग कर रहे हैं तो आप computeIfPresent मेथड का उपयोग कर सकते हैं । यदि निर्दिष्ट कुंजी के लिए मान मौजूद है और गैर-अशक्त है, तो यह कुंजी और इसके वर्तमान टैप किए गए मान को देखते हुए एक नई मैपिंग की गणना करने का प्रयास करता है।

final Map<String,Integer> map1 = new HashMap<>();
map1.put("A",0);
map1.put("B",0);
map1.computeIfPresent("B",(k,v)->v+1);  //[A=0, B=1]

हम एक कुंजी लगाने के लिए किसी अन्य विधि putIfAbsent का उपयोग भी कर सकते हैं । यदि निर्दिष्ट कुंजी पहले से ही एक मूल्य से जुड़ी नहीं है (या नल के लिए मैप की गई है) तो यह विधि इसे दिए गए मूल्य के साथ जोड़ देती है और शून्य मान देती है, अन्यथा वर्तमान मान लौटा देती है।

यदि नक्शा थ्रेड्स में साझा किया जाता है, तो हम ConcurrentHashMapऔर एटोमिकइंटर का उपयोग कर सकते हैं । डॉक्टर से:

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

हम उन्हें दिखाए गए अनुसार उपयोग कर सकते हैं:

final Map<String,AtomicInteger> map2 = new ConcurrentHashMap<>();
map2.putIfAbsent("A",new AtomicInteger(0));
map2.putIfAbsent("B",new AtomicInteger(0)); //[A=0, B=0]
map2.get("B").incrementAndGet();    //[A=0, B=1]

अवलोकन करने के लिए एक बिंदु यह है कि हम getकुंजी के लिए मान प्राप्त करने के लिए आह्वान कर रहे हैं Bऔर फिर incrementAndGet()इसके मूल्य पर आह्वान कर रहे हैं जो निश्चित रूप से है AtomicInteger। हम इसे अनुकूलित कर सकते हैं क्योंकि विधि putIfAbsentकुंजी के लिए मान लौटाता है यदि पहले से मौजूद है:

map2.putIfAbsent("B",new AtomicInteger(0)).incrementAndGet();//[A=0, B=2]

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



2

चूंकि मैं कम प्रतिष्ठा के कारण कुछ उत्तरों पर टिप्पणी नहीं कर सकता, मैं एक समाधान पोस्ट करूंगा जो मैंने लागू किया था।

for(String key : someArray)
{
   if(hashMap.containsKey(key)//will check if a particular key exist or not 
   {
      hashMap.put(hashMap.get(key),value+1);// increment the value by 1 to an already existing key
   }
   else
   {
      hashMap.put(key,value);// make a new entry into the hashmap
   }
}

1

forसूचकांक को बढ़ाने के लिए एक लूप का उपयोग करें :

for (int i =0; i<5; i++){
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("beer", 100);

    int beer = map.get("beer")+i;
    System.out.println("beer " + beer);
    System.out ....

}

3
यह सिर्फ प्रत्येक पुनरावृत्ति पर मानचित्र को अधिलेखित करेगा। सही दृष्टिकोण के लिए मैथ्यू का जवाब देखें।
लेह

1

इस प्रश्न के भ्रामक उत्तर यहां दिए गए हैं कि हैशटेबल पुट विधि मौजूदा मान को बदल देगी यदि कुंजी मौजूद है, तो यह हैशटेबल के लिए सही नहीं है, बल्कि हैशपे के लिए है। जावदोक को HashMap http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html#put%28K,%20V%29 के लिए देखें


1
Integer i = map.get(key);
if(i == null)
   i = (aValue)
map.put(key, i + 1);

या

Integer i = map.get(key);
map.put(key, i == null ? newValue : i + 1);

पूर्णांक आदिम डेटा प्रकार है http://cs.fit.edu/~ryan/java/language/java-data.html , इसलिए आपको इसे बाहर निकालने, कुछ प्रक्रिया करने की आवश्यकता है, फिर इसे वापस रखें। यदि आपके पास एक मूल्य है जो आदिम डेटा प्रकार नहीं है, तो आपको इसे केवल निकालने की ज़रूरत है, इसे संसाधित करना होगा, इसे वापस हैशमैप में डालने की आवश्यकता नहीं है।


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

0

प्रयत्न:

HashMap hm=new HashMap<String ,Double >();

ध्यान दें:

String->give the new value; //THIS IS THE KEY
else
Double->pass new value; //THIS IS THE VALUE

आप अपने हैशमैप में कुंजी या मान बदल सकते हैं, लेकिन आप एक ही समय में दोनों को नहीं बदल सकते।


0

'ComputeIfPresent' में बनाए गए Java8 का उपयोग करें

उदाहरण:

public class ExampleToUpdateMapValue {

    public static void main(String[] args) {
        Map<String,String> bookAuthors = new TreeMap<>();
        bookAuthors.put("Genesis","Moses");
        bookAuthors.put("Joshua","Joshua");
        bookAuthors.put("Judges","Samuel");

        System.out.println("---------------------Before----------------------");
        bookAuthors.entrySet().stream().forEach(System.out::println);
        // To update the existing value using Java 8
        bookAuthors.computeIfPresent("Judges", (k,v) -> v = "Samuel/Nathan/Gad");

        System.out.println("---------------------After----------------------");
        bookAuthors.entrySet().stream().forEach(System.out::println);
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.