নন-সন্ধান করা কীগুলির জন্য ডিফল্ট মানটি ফেরত দেওয়ার জন্য হাশম্যাপ?


151

এটি একটি আছে কি সম্ভব HashMapআগমন সমস্ত কী সেট পাওয়া যায় না জন্য ডিফল্ট মান?


আপনি কী অস্তিত্ব এবং ডিফল্ট ফিরে আসতে পরীক্ষা করতে পারেন। বা শ্রেণি প্রসারিত করুন এবং আচরণটি পরিবর্তন করুন। অথবা এমনকি আপনি নাল ব্যবহার করতে পারেন - এবং আপনি এটি যেদিকে ব্যবহার করতে চান সেখানে কিছু পরীক্ষা করুন।
সুধিরজে

2
এটি স্ট্যাকওভারফ্লো / প্রশ্নগুলি / 4833336 /… সম্পর্কিত / এর সদৃশ… কিছু অন্যান্য বিকল্প সেখানে আলোচনা করা হয়েছে।
মার্ক বাটলার

3
মানচিত্র এপিআই getOrDefault() লিঙ্কটির
ট্রে জন 3

উত্তর:


136

[হালনাগাদ]

অন্যান্য উত্তর এবং মন্তব্যকারীদের দ্বারা উল্লিখিত হিসাবে, জাভা 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;
  }
}

20
কেবল স্পষ্ট করে বলতে গেলে, তারা উদ্দেশ্যমূলকভাবে কোনও মান যুক্ত (v == null)করার (v == null && !this.containsKey(k))ক্ষেত্রে আপনি শর্তটি এ থেকে সামঞ্জস্য করতে চাইতে পারেন null। আমি জানি, এটি কেবল একটি কর্নার কেস তবে লেখক এটির মধ্যে চলে যেতে পারে।
অ্যাডাম পেইন্টার

@ ম্যারিক্স: আমি লক্ষ্য করেছি যে আপনি ব্যবহার করেছেন !this.containsValue(null)। এটি থেকে subtly পৃথক !this.containsKey(k)containsValueসমাধান যদি কিছু ব্যর্থ হবে অন্যান্য চাবি স্পষ্টভাবে মান অ্যাসাইন করা হয়েছে null। উদাহরণস্বরূপ: map = new HashMap(); map.put(k1, null); V v = map.get(k2);এই ক্ষেত্রে, vএখনও null, সঠিক হবে?
অ্যাডাম পেইন্টার

21
সাধারণভাবে , আমি মনে করি এটি একটি খারাপ ধারণা - আমি ক্লায়েন্টের মধ্যে ডিফল্ট আচরণ বা ম্যাপ হিসাবে দাবী না করে এমন একটি প্রতিনিধি চাপিয়ে দেব। বিশেষত, বৈধ কীসেট () বা এন্ট্রিসেট () এর অভাবে মানচিত্রে চুক্তিটি সম্মানের প্রত্যাশা করে এমন কোনও সমস্যা তৈরি করবে। এবং কী () দ্বারা বোঝা যায় এমন বৈধ কীগুলির অসীম সেটটি নির্ণয় করা শক্ত প্রতিক্রিয়ার কারণ হতে পারে। এটি বলার অপেক্ষা রাখে না যে এটি কোনও নির্দিষ্ট উদ্দেশ্যে কাজ করতে পারে না।
এড স্টাব

এই পদ্ধতির সাথে একটি সমস্যা হ'ল মানটি যদি কোনও জটিল জিনিস। মানচিত্র <স্ট্রিং, তালিকা> # পট প্রত্যাশা অনুযায়ী কাজ করবে না।
ইয়াল

কনকন্টারহ্যাশম্যাপে কাজ করে না। সেখানে, আপনার নাল জন্য ফলাফল পরীক্ষা করা উচিত।
dveim

162

জাভা 8-এ, Map.getOrDefault ব্যবহার করুন । এটি কীটি নেয় এবং যদি কোনও মেলানো কী না পাওয়া যায় তবে ফিরে আসতে মানটি লাগে।


14
getOrDefaultখুব সুন্দর, তবে প্রত্যেকবার মানচিত্রটি অ্যাক্সেস করার সময় ডিফল্ট সংজ্ঞা প্রয়োজন। কোনও ডিফল্ট মান একবারে সংজ্ঞায়িত করার সাথে মানগুলির স্থিতিশীল মানচিত্র তৈরি করার সময় পঠনযোগ্যতা সুবিধাও পাওয়া যায়।
অচ

3
নিজেকে বাস্তবায়নের পক্ষে এটি তুচ্ছ। private static String get(Map map, String s) { return map.getOrDefault(s, "Error"); }
জ্যাক স্যাট্রিয়ানো

@ জ্যাকস্যাট্রিয়ানো হ্যাঁ তবে আপনাকে ডিফল্ট মানটি হার্ড-কোড করতে হবে, বা এর জন্য একটি স্ট্যাটিক ভেরিয়েবল থাকতে হবে।
ব্লার্প

1
ডিফল্ট মান ব্যয়বহুল হয় বা প্রতিটি সময় পৃথক হওয়া উচিত ভাল, computeIfAbmitted ব্যবহার করে উত্তর নীচে দেখুন।
হেক্টরপাল

যদিও এটি মেমোরির জন্য খারাপ, এবং কেবল তখনই গণনার সময় সাশ্রয় হয় যদি ডিফল্ট মানটি নির্মান / গণনা করতে ব্যয় হয়। যদি এটি সস্তা হয় তবে আপনি সম্ভবত এটির চেয়ে খারাপ কার্য সম্পাদন করতে পারবেন কারণ এটি কেবলমাত্র একটি ডিফল্ট মান না দিয়ে মানচিত্রে সন্নিবেশ করতে হবে। অবশ্যই অন্য একটি বিকল্প।
স্পাইচো

73

আপনি যদি চক্রটিকে পুনর্সামকরণের মতো মনে করেন না, যেমন কমন্স'স ডিফল্টম্যাপ ব্যবহার করুন ,

Map<String, String> map = new DefaultedMap<>("[NO ENTRY FOUND]");
String surname = map.get("Surname"); 
// surname == "[NO ENTRY FOUND]"

আপনি যদি প্রথম স্থানে মানচিত্র তৈরির দায়িত্বে না থাকেন তবে আপনি কোনও বিদ্যমান মানচিত্রেও পাস করতে পারেন।


26
+1 যদিও মাঝে মাঝে সহজ কার্যকারিতার ক্ষুদ্র টুকরাগুলির জন্য বৃহত নির্ভরতা প্রবর্তনের চেয়ে চাকাটিকে পুনরায় উদ্ভাবন করা সহজ।
maerics

3
এবং মজার বিষয় হ'ল যে অনেক প্রকল্পের সাথে আমি কাজ করি তাদের ইতিমধ্যে ক্লাসপথে (অ্যাপাচি কমন্স বা গুগল পেয়ারা) এমন কিছু রয়েছে
ক্লাসপাথে বার্টোসজ.আর

@ বার্টোস.আর, অবশ্যই মোবাইলে নেই
পেসারিয়ার

44

জাভা 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/

দাবি অস্বীকারকারী : এই উত্তরটি ওপি যা বলেছিল ঠিক তার সাথে মেলে না তবে কিছু ক্ষেত্রে প্রশ্নের শিরোনামের সাথে মিলে যাওয়া কার্যকর হতে পারে যখন কী সংখ্যা সীমিত থাকে এবং বিভিন্ন মানকে ক্যাশে করা লাভজনক হবে। এটি বিপুল ক্ষেত্রে প্রচুর কী এবং একই ডিফল্ট মান হিসাবে ব্যবহার করা উচিত নয় কারণ এটি অযথা মেমোরি নষ্ট করে।


ওপি যা বলেছিল তা নয়: তিনি মানচিত্রে কোনও পার্শ্ব প্রতিক্রিয়া চান। এছাড়াও, প্রতিটি অনুপস্থিত কীটির জন্য ডিফল্ট মান সংরক্ষণ করা মেমরির স্থানের অকেজো ক্ষতি।
numéro6

@ numéro6, হ্যাঁ, এটি ওপি যা বলেছিল ঠিক তার সাথে মেলে না তবে কিছু গুগল মানুষ এই দিকের উত্তরকে দরকারী বলে মনে করেন। অন্যান্য জবাব যেমন উল্লিখিত হয়েছে, মানচিত্রের চুক্তি ভঙ্গ না করে ওপি যা বলেছিল ঠিক তা অর্জন করা অসম্ভব। এখানে উল্লেখ করা আরেকটি কার্যসংক্রান্ত হয় ম্যাপ পরিবর্তে অন্য বিমূর্ততা ব্যবহার
ভাদজিম

মানচিত্রের চুক্তি ভঙ্গ না করে ওপি যা বলেছিল ঠিক তা অর্জন সম্ভব। কোনও কর্মপরিক্রমা প্রয়োজন নেই, কেবল getOrDefault ব্যবহার করা সঠিক (সর্বাধিক আপডেট হওয়া) উপায়, কম্পিউটএফএবসেন্টটি ভুল উপায়: আপনি ফলাফলটি (প্রতিটি অনুপস্থিত কীগুলির জন্য উভয়ই) সংরক্ষণ করে ম্যাপিং ফাংশন এবং মেমরির কল করতে সময় হারাবেন। আমি getOrDefault এর পরিবর্তে এটি করার কোনও ভাল কারণ দেখতে পাচ্ছি না। আমি যা বর্ণনা করছি তা হ'ল ম্যাপ চুক্তিতে দুটি স্বতন্ত্র পদ্ধতি হ'ল সঠিক কারণ: দুটি স্বতন্ত্র ব্যবহারের কেস যা বিভ্রান্ত হওয়া উচিত নয় (আমাকে কিছু কাজ ঠিক করতে হয়েছিল)। এই উত্তর বিভ্রান্তি ছড়িয়ে পড়ে।
numéro6

14

আপনি কি ঠিক কোনও স্থির পদ্ধতি তৈরি করতে পারবেন না যা ঠিক এটি করে?

private static <K, V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
    return map.containsKey(key) ? map.get(key) : defaultValue;
}

স্ট্যাটিক কোথায় রাখবেন?
পেসারিয়ার

10

আপনি কেবলমাত্র নতুন ক্লাস তৈরি করতে পারেন যা হ্যাশম্যাপ উত্তরাধিকার সূত্রে প্রাপ্ত এবং 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;
    }
}

আমি মনে করি যে এড স্টাব তার মন্তব্যে নির্দিষ্ট কারণগুলির কারণে এবং আপনার মানচিত্র ইন্টারফেসের চুক্তিটি ভঙ্গ করবেন (সম্ভবত এটি কিছুটা কঠিন-সন্ধানের দিকে পরিচালিত করতে পারে ) কারণ আপনার বাস্তবায়নে আপনার (কে কী) পদ্ধতিটি ওভাররাইড করা উচিত নয় বাগ)।


4
আপনি getপদ্ধতিটি ওভাররাইড না করার একটি বিষয় পেয়েছেন । অন্যদিকে - আপনার সমাধানটি ইন্টারফেসের মাধ্যমে শ্রেণিটি ব্যবহারের অনুমতি দেয় না, যা প্রায়শই হতে পারে।
ক্রিজিসটফ জাবোসস্কি


3

এটি ডিফল্টরূপে এটি করে। এটি ফিরে আসে null


@ ল্যারি, পুরোপুরি HashMapঠিকঠাক হলে কেবল এই কার্যকারিতার জন্য সাবক্লাসে আমার কাছে কিছুটা নির্বোধ মনে nullহয়।
mrkhrts

15
আপনি যদি কোনও NullObjectপ্যাটার্ন ব্যবহার করেন তবে এটি ঠিক নয় , যদিও বা আপনার কোড জুড়ে নাল-চেকগুলি ছড়িয়ে দিতে চান না - এমন একটি ইচ্ছা যা আমি পুরোপুরি বুঝতে পারি।
ডেভ নিউটন


1

আমি লাজিমেপকে বেশ সহায়ক বলে মনে করেছি।

যখন মানচিত্রটিতে অস্তিত্ব নেই এমন কী দিয়ে get (অবজেক্ট) পদ্ধতিটি কল করা হয়, তখন কারখানাটি অবজেক্ট তৈরি করতে ব্যবহৃত হয়। অনুরোধ করা কীটি ব্যবহার করে তৈরি করা বস্তুটি মানচিত্রে যুক্ত করা হবে।

এটি আপনাকে এরকম কিছু করতে দেয়:

    Map<String, AtomicInteger> map = LazyMap.lazyMap(new HashMap<>(), ()->new AtomicInteger(0));
    map.get(notExistingKey).incrementAndGet();

getপ্রদত্ত কীটির জন্য একটি ডিফল্ট মান তৈরি করার কল । আপনি কারখানার যুক্তি দিয়ে কীভাবে ডিফল্ট মান তৈরি করবেন তা নির্দিষ্ট করে দিন LazyMap.lazyMap(map, factory)। উপরের উদাহরণে মানচিত্রটি AtomicInteger0 মান সহ নতুনতে সূচিত হয় ।


এটির কোনও গ্রহণযোগ্য উত্তরের চেয়ে একটি সুবিধা রয়েছে যে কোনও কারখানা দ্বারা ডিফল্ট মান তৈরি করা হয়। আমার ডিফল্ট মানটি কী হয় List<String>- গ্রহণযোগ্য উত্তরটি ব্যবহার করে আমি কারখানার একটি (বলার চেয়ে) পরিবর্তে প্রতিটি নতুন কীর জন্য একই তালিকাটি ব্যবহার করার ঝুঁকি নিয়ে থাকি new ArrayList<String>()

0

সরাসরি নয়, তবে ক্লাসের গেট পদ্ধতিটি পরিবর্তন করতে আপনি প্রসারিত করতে পারেন। উদাহরণটি ব্যবহারের জন্য এখানে প্রস্তুত: http://www.java2s.com/ কোড / জাভা / সংগ্রহগুলি- ডেটা- স্ট্রাকচার / এক্সটেন্ডেড ভার্সনফজাওটিল হ্যাশম্যাপট্যাটপ্রোভিডেসনেট এক্সেটেডজেডডাওডাওক্যাটিটিংডেফাল্টালুএইচটিএম


0
/**
 * 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));

0

আমার জেএসএনের একটি সার্ভার থেকে প্রাপ্ত ফলাফলগুলি পড়তে হবে যেখানে আমি ক্ষেত্রগুলি উপস্থিত থাকার গ্যারান্টি দিতে পারি না। আমি ক্লাস org.json.simple.JSONObject ব্যবহার করছি যা হ্যাশম্যাপ থেকে প্রাপ্ত। আমি নিযুক্ত কিছু সহায়ক কার্যাদি এখানে রয়েছে:

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.