হ্যাশম্যাপের হ্যাশম্যাপের সূচনা করার কোডটি পুনরাবৃত্তি করা এড়াতে পারি কীভাবে?


27

প্রত্যেক ক্লায়েন্টের একটি আইডি থাকে এবং অনেকগুলি চালান, তারিখ সহ, তারিখ অনুসারে চালকদের হ্যাশম্যাপের আইডি দ্বারা ক্লায়েন্টের হাশম্যাপ হিসাবে সঞ্চিত থাকে:

HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.get(id);

if(allInvoices!=null){
    allInvoices.put(date, invoice);      //<---REPEATED CODE
}else{
    allInvoices = new HashMap<>();
    allInvoices.put(date, invoice);      //<---REPEATED CODE
    allInvoicesAllClients.put(id, allInvoices);
}

জাভা সমাধানটি ব্যবহার করার মতো বলে মনে হচ্ছে getOrDefault:

HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.getOrDefault(
    id,
    new HashMap<LocalDateTime, Invoice> (){{  put(date, invoice); }}
);

তবে যদি প্রাপ্তিটি শূন্য না হয় তবে আমি এখনও (ডেট, চালান) কার্যকর করতে চাই এবং "allInvoicesAllClients" তে ডেটা যুক্ত করা এখনও দরকার। সুতরাং এটি অনেক সাহায্য করবে বলে মনে হয় না।


আপনি যদি কীটির স্বতন্ত্রতার গ্যারান্টি দিতে না পারেন তবে গৌণ মানচিত্রে কেবল ইনভয়েসের পরিবর্তে <ইনভয়েস> এর তালিকা থাকা ভাল you're
রায়ান

উত্তর:


39

এটি একটি দুর্দান্ত ব্যবহারের ক্ষেত্রে Map#computeIfAbsent। আপনার স্নিপেট মূলত: এর সমতুল্য

allInvoicesAllClients.computeIfAbsent(id, key -> new HashMap<>()).put(date, invoice);

যদি idকোনও কী হিসাবে উপস্থিত না থাকে allInvoicesAllClients, তবে এটি idনতুন থেকে ম্যাপিং তৈরি করবে এবং নতুনটি HashMapফিরিয়ে দেবে HashMap। যদি idকোনও কী হিসাবে উপস্থিত থাকে তবে তা বিদ্যমানটি ফিরিয়ে দেবে HashMap


1
computeIfAbmitted, একটি get (id) (বা একটি get (id)) দ্বারা একটি পুট দেয়, সুতরাং পরবর্তী পুস্তকটি সঠিক উত্তর (আইটেম) রাখার জন্য করা হয়, তারিখের সঠিক উত্তর।
হার্নান এচে

allInvoicesAllClients.computeIfAbsent(id, key -> Map.of(date, invoice))
আলেকজান্ডার - মনিকা

1
@ আলেকজান্ডার-রেইনস্টেটমোনিকা Map.ofএকটি অমার্জনীয়যোগ্য তৈরি করে Map, যা আমি নিশ্চিত না যে ওপি চায়।
জ্যাকব জি।

এই কোডটি ওপি মূলত যা ছিল তার চেয়ে কম দক্ষ হবে? এটি জিজ্ঞাসা করা হচ্ছে কারণ জাভা কীভাবে ল্যাম্বডা কার্য পরিচালনা করে তা সম্পর্কে আমি পরিচিত নই।
জেকং হু

16

computeIfAbsentএই বিশেষ ক্ষেত্রে জন্য একটি দুর্দান্ত সমাধান। সাধারণভাবে, আমি নিম্নলিখিতগুলি লক্ষ্য করতে চাই, যেহেতু কেউই এখনও এটি উল্লেখ করেছে:

"বহিরাগত" হ্যাশম্যাপটি কেবলমাত্র "অভ্যন্তরীণ" হ্যাশম্যাপের একটি রেফারেন্স সঞ্চয় করে , তাই কোডের সদৃশতা এড়াতে আপনি কেবল ক্রিয়াকলাপগুলি পুনরায় অর্ডার করতে পারেন:

HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.get(id);

if (allInvoices == null) {           
    allInvoices = new HashMap<>();
    allInvoicesAllClients.put(id, allInvoices);
}

allInvoices.put(date, invoice);      // <--- no longer repeated

জাভা 8 এর অভিনব computeIfAbsent()পদ্ধতিটি বয়ে আনার আগে আমরা এভাবে কয়েক দশক ধরে এটি করেছিলাম !
নিল বারলেটলেট

1
আমি আজও এই পদ্ধতির ভাষাগুলি সেই ভাষাগুলিতে ব্যবহার করি যেখানে মানচিত্রের প্রয়োগটি কোনও একা গেট-অর-পুট-এবং-রিটার্ন-যদি-অনুপস্থিত পদ্ধতি সরবরাহ করে না। এটি অন্যান্য ভাষায় এটি এখনও সেরা সমাধান হতে পারে তা উল্লেখযোগ্য হতে পারে যদিও এই প্রশ্নটি জাভা ৮ এর জন্য বিশেষভাবে ট্যাগ করা হয়েছে
কুইন মর্টিমার

11

আপনার কখনও কখনও "ডাবল ব্রেস" মানচিত্রের আরম্ভের ব্যবহার করা উচিত নয়।

{{  put(date, invoice); }}

এই ক্ষেত্রে, আপনার ব্যবহার করা উচিত computeIfAbsent

allInvoicesAllClients.computeIfAbsent(id, (k) -> new HashMap<>())
                     .put(date, allInvoices);

এই আইডির জন্য যদি কোনও মানচিত্র না থাকে তবে আপনি একটি প্রবেশ করান। ফলাফলটি বিদ্যমান বা গণিত মানচিত্রের হবে। তারপরে আপনি putগ্যারান্টি সহ সেই মানচিত্রে আইটেমগুলি রাখতে পারেন যে এটি বাতিল হবে না।


1
আমি জানি না কারা কমেছে, আমাকে নয়, সম্ভবত একক লাইন কোডটি সমস্ত বিভ্রান্ত করছে সব ইনভয়েসসস সমস্ত ক্লায়েন্টস, কারণ আপনি তারিখের পরিবর্তে আইডি ব্যবহার করেন, আমি এটি সম্পাদনা করব
হার্নান এচে

1
@ হার্নেনএচে আহ আমার ভুল. ধন্যবাদ। হ্যাঁ পুট idএছাড়াও সম্পন্ন করা হয়। আপনি চাইলে computeIfAbsentশর্তসাপেক্ষ হিসাবে ভাবতে পারেন। এবং এটি মানটিও প্রদান করে
মাইকেল

" আপনার" ডাবল ব্রেস "মানচিত্রের সূচনাটি ব্যবহার করা উচিত নয় ?" কেন? (আপনি ঠিক বলেছেন যে আমি সন্দেহ করি না; আমি আসল কৌতূহল নিয়ে জিজ্ঞাসা করছি))
হেইনজি

1
@ হেইনজি কারণ এটি একটি বেনামে অভ্যন্তর শ্রেণি তৈরি করে। এটি ক্লাসটির একটি রেফারেন্স ধারণ করে যা এটি ঘোষণা করেছিল, যা আপনি যদি মানচিত্রটি প্রকাশ করেন (উদাহরণস্বরূপ একজন গেটারের মাধ্যমে) বেষ্টনকারী শ্রেণিকে আবর্জনা সংগ্রহ করা থেকে আটকাবে। এছাড়াও, আমি এটি জাভা সম্পর্কে কম পরিচিত মানুষের জন্য বিভ্রান্তিকর হতে পারে বলে মনে করি; ইনিশিয়ালাইজার ব্লকগুলি খুব কমই ব্যবহার করা হয় এবং এ জাতীয় লেখা এটি দেখতে দেখতে সুন্দর করে তোলে{{ }} বিশেষ অর্থ হয়, যা তা নয়।
মাইকেল

1
@ মিশেল: অর্থবোধ, ধন্যবাদ। আমি সম্পূর্ণরূপে ভুলে গেছি যে বেনামি অভ্যন্তরীণ ক্লাসগুলি সর্বদা অ স্থির থাকে (এমনকি তাদের প্রয়োজন না হলেও)।
হেইঞ্জি

5

এটি অন্যান্য উত্তরের চেয়ে দীর্ঘ, তবে imho আরও বেশি পাঠযোগ্য:

if(!allInvoicesAllClients.containsKey(id))
    allInvoicesAllClients.put(id, new HashMap<LocalDateTime, Invoice>());

allInvoicesAllClients.get(id).put(date, invoice);

3
এটি কোনও হ্যাশম্যাপের জন্য কাজ করতে পারে তবে সাধারণ পন্থা অনুকূল নয়। এগুলি যদি কনকেনেন্টহ্যাশম্যাপস হয় তবে এই ক্রিয়াকলাপগুলি পারমাণবিক নয়। এই ক্ষেত্রে, চেক-এরপরে আইন জাতিগত অবস্থার দিকে পরিচালিত করবে। যাহাই হউক না কেন, বিদ্বেষী
মাইকেল

0

আপনি এখানে দুটি পৃথক কাজ করছেন: তা নিশ্চিত করে HashMap বিদ্যমান রয়েছে এবং এতে নতুন এন্ট্রি যুক্ত করা।

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

সুতরাং, @ হাইঞ্জির পরামর্শ অনুসারে, আপনি কেবল এই দুটি পদক্ষেপ বিভক্ত করতে পারেন।

কি আমিও করবেন সৃষ্টির অফলোড হয় HashMapকরতে allInvoicesAllClients, বস্তুর তাই getপদ্ধতি আর আসতে পারবেন নাnull

এটি পৃথক থ্রেডের মধ্যে দৌড়ের সম্ভাবনাও হ্রাস করে যা উভয় nullথেকেই পয়েন্টার পেতে পারে getএবং পরে একটি একক প্রবেশের মাধ্যমে putএকটি নতুন স্থির করে নিতে পারে HashMap- দ্বিতীয়টি putসম্ভবত Invoiceঅবজেক্টটি হারাতে পারলে প্রথমটিকে ফেলে দেয় ।

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