क्या HashMap
सभी कुंजियों के लिए डिफ़ॉल्ट मान होना संभव है जो सेट में नहीं मिले हैं?
getOrDefault()
लिंक के
क्या HashMap
सभी कुंजियों के लिए डिफ़ॉल्ट मान होना संभव है जो सेट में नहीं मिले हैं?
getOrDefault()
लिंक के
जवाबों:
[अपडेट करें]
जैसा कि अन्य उत्तर और टिप्पणीकारों ने कहा है, जावा 8 के रूप में आप बस कॉल कर सकते हैं Map#getOrDefault(...)
।
[मूल रूप]
कोई मानचित्र कार्यान्वयन नहीं है जो इसे ठीक करता है, लेकिन हैशपॉप का विस्तार करके अपने स्वयं को लागू करना तुच्छ होगा:
public class DefaultHashMap<K,V> extends HashMap<K,V> {
protected V defaultValue;
public DefaultHashMap(V defaultValue) {
this.defaultValue = defaultValue;
}
@Override
public V get(Object k) {
return containsKey(k) ? super.get(k) : defaultValue;
}
}
(v == null)
के लिए (v == null && !this.containsKey(k))
मामले में वे जानबूझकर एक जोड़ा null
मूल्य। मुझे पता है, यह सिर्फ एक कोने का मामला है, लेकिन लेखक इसमें भाग सकता है।
!this.containsValue(null)
। यह सूक्ष्म रूप से भिन्न है !this.containsKey(k)
। containsValue
समाधान यदि कुछ असफल हो जायेगी अन्य कुंजी स्पष्ट रूप से एक मूल्य सौंपा गया है null
। उदाहरण के लिए: map = new HashMap(); map.put(k1, null); V v = map.get(k2);
इस मामले में, v
अभी भी null
सही होगा?
जावा 8 में, Map.getOrDefault का उपयोग करें । यह कुंजी लेता है, और कोई मिलान कुंजी नहीं मिलने पर वापस जाने के लिए मान।
getOrDefault
बहुत अच्छा है, लेकिन हर बार नक्शे तक पहुँचने के लिए डिफ़ॉल्ट परिभाषा की आवश्यकता होती है। मूल्यों का स्थैतिक मानचित्र बनाते समय डिफ़ॉल्ट मान को एक बार परिभाषित करने से पठनीयता लाभ भी होगा।
private static String get(Map map, String s) { return map.getOrDefault(s, "Error"); }
यदि आप पहिया को फिर से स्थापित करने की तरह महसूस नहीं करते हैं, तो कॉमन्स के डिफॉल्टपाइप का उपयोग करें , जैसे,
Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname");
// surname == "[NO ENTRY FOUND]"
यदि आप पहले स्थान पर नक्शा बनाने के प्रभारी नहीं हैं, तो आप एक मौजूदा नक्शे में भी पास कर सकते हैं।
जावा 8 ने इंटरफ़ेस के लिए एक अच्छा कम्प्यूटेशनल डिफ़ॉल्ट डिफॉल्ट विधि पेश की, Map
जो आलसी-गणना मूल्य को संग्रहीत करता है और इसलिए नक्शा अनुबंध को नहीं तोड़ता है:
Map<Key, Graph> map = new HashMap<>();
map.computeIfAbsent(aKey, key -> createExpensiveGraph(key));
उत्पत्ति: http://blog.javabien.net/2014/02/20/loadingcache-in-java-8-without-guava/
विस्मयादिबोधक: यह उत्तर ठीक उसी तरह से मेल नहीं खाता है जो ओपी ने पूछा था, लेकिन कुछ मामलों में प्रश्न के शीर्षक से मेल खा सकता है जब कुंजी संख्या सीमित है और विभिन्न मूल्यों का कैशिंग लाभदायक होगा। यह विपरीत कुंजी और समान डिफ़ॉल्ट मान के साथ विपरीत मामले में उपयोग नहीं किया जाना चाहिए क्योंकि यह अनावश्यक रूप से स्मृति को बेकार कर देगा।
क्या आप सिर्फ एक स्थैतिक विधि नहीं बना सकते हैं जो वास्तव में ऐसा करती है?
private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
return map.containsKey(key) ? map.get(key) : defaultValue;
}
आप बस एक नया वर्ग बना सकते हैं जो HashMap को इनहेरिट करता है और getDefault मेथड जोड़ता है। यहाँ एक नमूना कोड है:
public class DefaultHashMap<K,V> extends HashMap<K,V> {
public V getDefault(K key, V defaultValue) {
if (containsKey(key)) {
return get(key);
}
return defaultValue;
}
}
मुझे लगता है कि आपको अपने कार्यान्वयन में कारण (K कुंजी) विधि को ओवरराइड नहीं करना चाहिए, क्योंकि एड स्टॉब ने उनकी टिप्पणी में निर्दिष्ट कारणों के कारण और क्योंकि आप मैप इंटरफ़ेस के अनुबंध को तोड़ देंगे (यह संभवतः कुछ हार्ड-टू-फाइंड को जन्म दे सकता है कीड़े)।
get
विधि को ओवरराइड नहीं करने का एक बिंदु मिला है । दूसरी ओर - आपका समाधान इंटरफ़ेस के माध्यम से कक्षा का उपयोग करने की अनुमति नहीं देता है, जो अक्सर मामला हो सकता है।
उपयोग:
myHashMap.getOrDefault(key, defaultValue);
यह डिफ़ॉल्ट रूप से ऐसा करता है। यह लौट आता है null
।
HashMap
इस कार्यक्षमता के लिए थोड़ा उपहास करने के लिए थोड़ा मूर्खतापूर्ण लगता है जब null
पूरी तरह से ठीक है।
NullObject
पैटर्न का उपयोग कर रहे हैं , हालांकि, या अपने कोड में अशक्त-चेक को बिखेरना नहीं चाहते हैं - एक इच्छा जिसे मैं पूरी तरह से समझता हूं।
मुझे LazyMap काफी मददगार लगा।
जब एक ऑब्जेक्ट के साथ गेट (ऑब्जेक्ट) विधि को बुलाया जाता है जो नक्शे में मौजूद नहीं होता है, तो फैक्ट्री का उपयोग ऑब्जेक्ट बनाने के लिए किया जाता है। अनुरोधित कुंजी का उपयोग करके बनाई गई वस्तु को मानचित्र में जोड़ा जाएगा।
यह आपको कुछ इस तरह से करने की अनुमति देता है:
Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
map.get(notExistingKey).incrementAndGet();
get
दी गई कुंजी के लिए डिफ़ॉल्ट मान बनाने के लिए कॉल । आप निर्दिष्ट करें कि फ़ैक्टरी तर्क के साथ डिफ़ॉल्ट मान कैसे बनाया जाए LazyMap.lazyMap(map, factory)
। ऊपर दिए गए उदाहरण में, मानचित्र को AtomicInteger
मान 0 के साथ एक नए से आरंभ किया गया है ।
सीधे तौर पर नहीं, लेकिन आप इसकी प्राप्त विधि को संशोधित करने के लिए कक्षा का विस्तार कर सकते हैं। यहाँ उदाहरण का उपयोग करने के लिए तैयार है: http://www.java2s.com/Code/Java/Collections-Data-Structure/ExtendedVersionofjavautilHashMapthatprovidesanextendedgetmethgetaccacingingadefaultvalue.htm
/**
* Extension of TreeMap to provide default value getter/creator.
*
* NOTE: This class performs no null key or value checking.
*
* @author N David Brown
*
* @param <K> Key type
* @param <V> Value type
*/
public abstract class Hash<K, V> extends TreeMap<K, V> {
private static final long serialVersionUID = 1905150272531272505L;
/**
* Same as {@link #get(Object)} but first stores result of
* {@link #create(Object)} under given key if key doesn't exist.
*
* @param k
* @return
*/
public V getOrCreate(final K k) {
V v = get(k);
if (v == null) {
v = create(k);
put(k, v);
}
return v;
}
/**
* Same as {@link #get(Object)} but returns specified default value
* if key doesn't exist. Note that default value isn't automatically
* stored under the given key.
*
* @param k
* @param _default
* @return
*/
public V getDefault(final K k, final V _default) {
V v = get(k);
return v == null ? _default : v;
}
/**
* Creates a default value for the specified key.
*
* @param k
* @return
*/
abstract protected V create(final K k);
}
उदाहरण उपयोग:
protected class HashList extends Hash<String, ArrayList<String>> {
private static final long serialVersionUID = 6658900478219817746L;
@Override
public ArrayList<Short> create(Short key) {
return new ArrayList<Short>();
}
}
final HashList haystack = new HashList();
final String needle = "hide and";
haystack.getOrCreate(needle).add("seek")
System.out.println(haystack.get(needle).get(0));
मुझे JSON में एक सर्वर से लौटाए गए परिणामों को पढ़ने की आवश्यकता है जहां मैं गारंटी नहीं दे सकता कि फ़ील्ड मौजूद होंगे। मैं class org.json.simple.JSONObject का उपयोग कर रहा हूं, जो HashMap से लिया गया है। यहाँ कुछ सहायक कार्य दिए गए हैं:
public static String getString( final JSONObject response,
final String key )
{ return getString( response, key, "" ); }
public static String getString( final JSONObject response,
final String key, final String defVal )
{ return response.containsKey( key ) ? (String)response.get( key ) : defVal; }
public static long getLong( final JSONObject response,
final String key )
{ return getLong( response, key, 0 ); }
public static long getLong( final JSONObject response,
final String key, final long defVal )
{ return response.containsKey( key ) ? (long)response.get( key ) : defVal; }
public static float getFloat( final JSONObject response,
final String key )
{ return getFloat( response, key, 0.0f ); }
public static float getFloat( final JSONObject response,
final String key, final float defVal )
{ return response.containsKey( key ) ? (float)response.get( key ) : defVal; }
public static List<JSONObject> getList( final JSONObject response,
final String key )
{ return getList( response, key, new ArrayList<JSONObject>() ); }
public static List<JSONObject> getList( final JSONObject response,
final String key, final List<JSONObject> defVal ) {
try { return response.containsKey( key ) ? (List<JSONObject>) response.get( key ) : defVal; }
catch( ClassCastException e ) { return defVal; }
}
मिश्रित जावा / कोटलिन परियोजनाओं में भी कोटलिन के Map.withDefault पर विचार करें ।