অভিধানে অ্যাডারেঞ্জ নেই কেন?


115

শিরোনাম যথেষ্ট বেসিক, আমি কেন করতে পারি না:

Dictionary<string, string> dic = new Dictionary<string, string>();
dic.AddRange(MethodThatReturnAnotherDic());


2
এমন অনেকগুলি রয়েছে যার অ্যাড্রেঞ্জ নেই, যা সর্বদা আমাকে মীমাংসিত করে। সংগ্রহের মতো <>। তালিকাটি <> এর কাছে রয়েছে এমনটি কেবল সর্বদা বিশ্রী মনে হয়েছিল, তবে সংগ্রহ <> বা অন্যান্য আইলিস্ট এবং আইকোলিকেশন অবজেক্ট নয়।
টিম

39
আমি এখানে একটি এরিক লিপার্ট টানতে যাচ্ছি: "কারণ সেই বৈশিষ্ট্যটি ডিজাইন, নির্দিষ্ট, প্রয়োগ, পরীক্ষামূলক, নথিভুক্ত ও প্রেরণ করা হয়নি।"
গাবে মোথার্ট

3
@ গ্যাবে মোথার্ট - আমি যা অনুমান করেছি ঠিক তা-ই। আমি অন্য লোকের উপর এই লাইনটি ব্যবহার করতে পছন্দ করি। যদিও তারা এটি ঘৃণা করে। :)
টিম

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

উত্তর:


76

মূল প্রশ্নের একটি মন্তব্য এটির বেশ ভাল যোগ করে:

কারণ এই বৈশিষ্ট্যটি ডিজাইন, নির্দিষ্ট, প্রয়োগ, পরীক্ষিত, নথিভুক্ত ও শিপড কেউই করেনি। - @ গাবে মোথার্ট

কেন? ঠিক আছে, সম্ভবত কারণ মার্জিং অভিধানগুলির আচরণের ফ্রেমওয়ার্ক নির্দেশিকাগুলির সাথে মানানসই এমন পদ্ধতিতে যুক্তিযুক্ত হতে পারে না।

AddRangeতথ্যের পরিসীমা সদৃশ এন্ট্রিগুলির জন্য মঞ্জুরি দেওয়ার কারণে কোনও সীমাবদ্ধ কোনও ধারক কনটেইনারটির কোনও অর্থ হয় না বলে উপস্থিত নেই। যেমন আপনার যদি IEnumerable<KeyValuePair<K,T>>সংগ্রহ থাকে তবে সদৃশ এন্ট্রি থেকে রক্ষা না করে।

কী-মান জোড়ের সংকলন যুক্ত করতে, এমনকি দুটি অভিধান একত্রিত করার আচরণটি সরাসরি-এগিয়ে। একাধিক সদৃশ এন্ট্রিগুলি কীভাবে মোকাবেলা করা উচিত তা আচরণ নয়।

কোনও সদৃশ নিয়ে কাজ করার সময় পদ্ধতির আচরণ কী হওয়া উচিত?

আমি ভাবতে পারি এমন কমপক্ষে তিনটি সমাধান রয়েছে:

  1. প্রথম প্রবেশের জন্য একটি ব্যতিক্রম নকল যা নকল
  2. একটি ব্যতিক্রম নিক্ষেপ করুন যাতে সমস্ত সদৃশ এন্ট্রি রয়েছে
  3. সদৃশ উপেক্ষা করুন

যখন একটি ব্যতিক্রম নিক্ষেপ করা হয়, মূল অভিধানের অবস্থাটি কী হওয়া উচিত?

Addপ্রায় সর্বদা একটি পারমাণবিক অপারেশন হিসাবে প্রয়োগ করা হয়: এটি সংগ্রহের সাফল্য এবং আপডেট করে বা ব্যর্থ হয় এবং সংগ্রহের অবস্থা অপরিবর্তিত থাকে। AddRangeসদৃশ ত্রুটির কারণে যেমন ব্যর্থ হতে পারে, তার আচরণের সাথে সামঞ্জস্য রাখার উপায় Addহ'ল কোনও অনুলিপিতে একটি ব্যতিক্রম ছড়িয়ে এটিকে পারমাণবিক করা এবং মূল অভিধানের অবস্থাটি অপরিবর্তিত হিসাবে রেখে দেওয়া।

একটি API গ্রাহক হিসাবে, পুনরাবৃত্তভাবে সদৃশ উপাদানগুলি সরিয়ে ফেলা বিরক্তিকর হবে, যার দ্বারা বোঝা যায় যে সমস্ত ডুপ্লিকেট মান AddRangeরয়েছে এমন একক ব্যতিক্রম ছড়িয়ে দেওয়া উচিত ।

পছন্দটি তখন এতে সিদ্ধ হয়:

  1. মূল অভিধানটি একা রেখে সমস্ত নকলের সাথে একটি ব্যতিক্রম ছুঁড়ে ফেলুন।
  2. সদৃশ উপেক্ষা করুন এবং এগিয়ে যান।

উভয় ব্যবহারের ক্ষেত্রে সমর্থন করার পক্ষে যুক্তি রয়েছে। এটি করতে, আপনি কি IgnoreDuplicatesস্বাক্ষরে একটি পতাকা যুক্ত করবেন?

IgnoreDuplicatesপতাকা (যখন সত্যতে সেট) ও অন্তর্নিহিত বাস্তবায়ন যেমন, আপ উল্লেখযোগ্য গতি প্রদান করবে would ডুপ্লিকেট পরীক্ষণ কোড বাইপাস।

সুতরাং, এখন আপনার কাছে একটি পতাকা রয়েছে যা AddRangeউভয় ক্ষেত্রেই সমর্থন করতে সহায়তা করে তবে এর একটি অনিবন্ধিত পার্শ্ব প্রতিক্রিয়া রয়েছে (যা এমন কিছু যা ফ্রেমওয়ার্ক ডিজাইনাররা এড়াতে সত্যিই কঠোর পরিশ্রম করেছিল)।

সারসংক্ষেপ

সদৃশদের সাথে ডিল করার ক্ষেত্রে যখন কোনও স্পষ্ট, সামঞ্জস্যপূর্ণ এবং প্রত্যাশিত আচরণ নেই, সেহেতু তাদের সকলের সাথে একত্রে আচরণ করা এবং শুরু করার পদ্ধতিটি সরবরাহ না করা সহজ।

আপনি যদি নিজেকে ক্রমাগত অভিধানগুলিকে মার্জ করতে দেখেন তবে আপনি অবশ্যই অভিধানগুলিকে মার্জ করার জন্য আপনার নিজের এক্সটেনশন পদ্ধতিটি লিখতে পারেন যা আপনার অ্যাপ্লিকেশন (গুলি) এর জন্য কাজ করে এমনভাবে আচরণ করবে।


37
সম্পূর্ণ মিথ্যা, একটি অভিধানের একটি অ্যাড্রেঞ্জ থাকতে হবে (IEnumerable <KeyValuePair <K, T >> মান)
গুসমান

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

5
AddMultipleAddRangeএর বাস্তবায়নটি উইঙ্কি হতে চলেছে তা নির্বিশেষে ভিন্ন : আপনি কি সমস্ত ডুপ্লিকেট কীগুলির একটি অ্যারে দিয়ে একটি ব্যতিক্রম ছুঁড়েন ? অথবা আপনি যে প্রথম ডুপ্লিকেট কীটির মুখোমুখি হয়েছেন তাতে কি ব্যতিক্রম ছুঁড়ে মারছেন? যদি কোনও ব্যতিক্রম ছুঁড়ে দেওয়া হয় তবে অভিধানের অবস্থাটি কী হওয়া উচিত? প্রিস্টাইন, বা সমস্ত কী কী সফল হয়েছিল?
অ্যালান

3
ঠিক আছে, সুতরাং এখন আমাকে নিজেই আমার গণনার পুনরাবৃত্তি করতে হবে এবং আপনার উল্লিখিত নকল সম্পর্কে সমস্ত সতর্কতা সহ পৃথকভাবে এগুলি যুক্ত করতে হবে। ফ্রেমওয়ার্ক থেকে বাদ দেওয়া কীভাবে কোনও সমস্যার সমাধান করে?

4
@ doug65536 কারণ আপনি, এপিআই ভোক্তা হিসাবে, এখন সিদ্ধান্ত নিতে পারেন কি প্রতিটি দিয়ে কি করতে চান Add- হয় প্রতিটি মোড়ানো Addএকটি try...catchএবং অনুরূপ ধরতে উপায় যে; বা সূচক ব্যবহার করুন এবং পরবর্তী মানটি দিয়ে প্রথম মানটি ওভাররাইট করুন; বা প্রিমিটিভলি ContainsKeyচেষ্টা করার আগে ব্যবহার করে পরীক্ষা করুন Add, এভাবে মূল মান সংরক্ষণ করা। যদি কাঠামোর কোনও AddRangeবা AddMultipleপদ্ধতি থাকে, তবে যা ঘটেছিল তার যোগাযোগের একমাত্র সহজ উপায়টি ব্যতিক্রমের মধ্য দিয়ে ছিল এবং জড়িত হ্যান্ডলিং এবং পুনরুদ্ধার কোনও কম জটিল হবে না।
জেভ স্পিটজ

36

আমি কিছু সমাধান পেয়েছি:

Dictionary<string, string> mainDic = new Dictionary<string, string>() { 
    { "Key1", "Value1" },
    { "Key2", "Value2.1" },
};
Dictionary<string, string> additionalDic= new Dictionary<string, string>() { 
    { "Key2", "Value2.2" },
    { "Key3", "Value3" },
};
mainDic.AddRangeOverride(additionalDic); // Overrides all existing keys
// or
mainDic.AddRangeNewOnly(additionalDic); // Adds new keys only
// or
mainDic.AddRange(additionalDic); // Throws an error if keys already exist
// or
if (!mainDic.ContainsKeys(additionalDic.Keys)) // Checks if keys don't exist
{
    mainDic.AddRange(additionalDic);
}

...

namespace MyProject.Helper
{
  public static class CollectionHelper
  {
    public static void AddRangeOverride<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
    {
        dicToAdd.ForEach(x => dic[x.Key] = x.Value);
    }

    public static void AddRangeNewOnly<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
    {
        dicToAdd.ForEach(x => { if (!dic.ContainsKey(x.Key)) dic.Add(x.Key, x.Value); });
    }

    public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
    {
        dicToAdd.ForEach(x => dic.Add(x.Key, x.Value));
    }

    public static bool ContainsKeys<TKey, TValue>(this IDictionary<TKey, TValue> dic, IEnumerable<TKey> keys)
    {
        bool result = false;
        keys.ForEachOrBreak((x) => { result = dic.ContainsKey(x); return result; });
        return result;
    }

    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (var item in source)
            action(item);
    }

    public static void ForEachOrBreak<T>(this IEnumerable<T> source, Func<T, bool> func)
    {
        foreach (var item in source)
        {
            bool result = func(item);
            if (result) break;
        }
    }
  }
}

আনন্দ কর.


আপনার দরকার নেই ToList(), একটি অভিধান একটি IEnumerable<KeyValuePair<TKey,TValue>। এছাড়াও, আপনি যদি বিদ্যমান কী মান যুক্ত করেন তবে দ্বিতীয় এবং তৃতীয় পদ্ধতির পদ্ধতিগুলি নিক্ষেপ করবে। না একটি ভাল ধারণা, আপনি এ খুঁজছেন সেটা TryAdd? অবশেষে, দ্বিতীয়টি প্রতিস্থাপন করা যাবেWhere(pair->!dic.ContainsKey(pair.Key)...
পানাগিওটিস কানভোস

2
ঠিক আছে, ToList()ভাল সমাধান নয় তাই আমি কোডটি পরিবর্তন করেছি। আপনি try { mainDic.AddRange(addDic); } catch { do something }যদি তৃতীয় পদ্ধতির বিষয়ে নিশ্চিত না হন তবে আপনি ব্যবহার করতে পারেন । দ্বিতীয় পদ্ধতিটি নিখুঁতভাবে কাজ করে।
এডিএম-আইটি

হাই পানাজিওটিস কানভোস, আমি আশা করি আপনি খুশি।
এডিএম-আইটি

1
আপনাকে ধন্যবাদ, আমি এটি চুরি করেছি।
বিপাক

14

যদি কেউ এই প্রশ্নটি আমার মতো করে আসে - তবে আইননামারেবল এক্সটেনশন পদ্ধতি ব্যবহার করে "অ্যাডরেঞ্জ" অর্জন করা সম্ভব:

var combined =
    dict1.Union(dict2)
        .GroupBy(kvp => kvp.Key)
        .Select(grp => grp.First())
        .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

অভিধান সংযুক্ত করার সময় প্রধান কৌশলটি সদৃশ কীগুলির সাথে কাজ করে। উপরের কোডে এটি অংশ .Select(grp => grp.First())। এক্ষেত্রে এটি অনুলিপিগুলির গ্রুপ থেকে সহজভাবে প্রথম উপাদান নেয় তবে প্রয়োজন হলে আপনি আরও পরিশীলিত যুক্তি প্রয়োগ করতে পারেন।


যদি ডিফল্ট সমতা তুলনামূলক ব্যবহার dict1 না করে ?
mjwills

লিংক পদ্ধতিগুলি আপনাকে প্রাসঙ্গিক হলে আইক্যুয়ালিটি কম্পিউটারে পাস করতে দেয়:var combined = dict1.Concat(dict2).GroupBy(kvp => kvp.Key, dict1.Comparer).ToDictionary(grp => grp.Key, grp=> grp.First(), dict1.Comparer);
কাইল ম্যাকক্লেলান

12

আমার অনুমানটি যা হয়েছে তা হিসাবে ব্যবহারকারীর যথাযথ আউটপুটের অভাব। আপনার অভিধানে পুনরাবৃত্তি কীগুলি থাকতে পারে না, যেখানে কিছু কী ছেদ করে যেখানে আপনি দুটি অভিধান মার্জ করবেন তা কীভাবে পরিচালনা করবেন? নিশ্চিতভাবে আপনি বলতে পারেন: "আমি যত্ন করি না" তবে এটি পুনরাবৃত্তি কীগুলির জন্য মিথ্যা / ফেরত দেওয়ার ব্যপারটি ভেঙে চলেছে breaking


5
আপনি যখন কল করেন তখন কী কী সংঘর্ষ Addহয় তার থেকে এটি কীভাবে আলাদা, তা ছাড়াও এটি একাধিকবার ঘটতে পারে। এটি একই ArgumentExceptionযে নিক্ষেপ করবে Add, অবশ্যই?
নিকোডেমাস 13

1
@ নিকোডেমাস 13 হ্যাঁ, তবে আপনি কী জানেন না কোন কীটি ব্যতিক্রমটি ছুঁড়েছে, কেবলমাত্র কিছু কীটি পুনরাবৃত্তি হয়েছিল।
গাল

1
@ গাল মঞ্জুর করেছেন, তবে আপনি পারবেন: ব্যতিক্রম বার্তায় বিবাদী কীটির নামটি ফিরিয়ে দিতে পারেন (কারও পক্ষে দরকারী যে তারা কী করছেন জানেন, আমি মনে করি ...), বা আপনি এটি (অংশ হিসাবে?) হিসাবে রাখতে পারেন আপনি যে আর্গুমেন্টইসেপশনটি নিক্ষেপ করেন সে সম্পর্কে প্যারামনেম আর্গুমেন্ট, বা-ওআর, আপনি একটি নতুন ব্যতিক্রম প্রকার তৈরি করতে পারেন (সম্ভবত একটি জেনেরিক পর্যাপ্ত বিকল্প হতে পারে NamedElementException??), হয় পরিবর্তে নিক্ষেপ করা হয় বা একটি আর্গুমেন্টএক্সসেপশনটির অভ্যন্তরীণ ধারণা হিসাবে চিহ্নিত হয় যা বিরোধিত নামযুক্ত উপাদানকে নির্দিষ্ট করে ... কয়েকটি ভিন্ন বিকল্প, আমি বলব
কোড জকি

7

আপনি এটি করতে পারে

Dictionary<string, string> dic = new Dictionary<string, string>();
// dictionary other items already added.
MethodThatReturnAnotherDic(dic);

public void MethodThatReturnAnotherDic(Dictionary<string, string> dic)
{
    dic.Add(.., ..);
}

অথবা অ্যাড্রেঞ্জ এবং / অথবা উপরের প্যাটার্নটি ব্যবহার করার জন্য একটি তালিকা ব্যবহার করুন।

List<KeyValuePair<string, string>>


1
ওপি যোগ করতে চায়, কোনও অভিধান ক্লোন করতে নয়। আমার উদাহরণে পদ্ধতিটির নাম হিসাবে MethodThatReturnAnotherDic। এটি ওপি থেকে আসে। প্রশ্ন এবং আমার উত্তর আবার পর্যালোচনা করুন।
ভালামাস

1

আপনি যদি ডাব্লু / একটি নতুন অভিধান (এবং আপনার কাছে বিদ্যমান সারিগুলি হারাতে না পারে) ডিল করে থাকেন তবে আপনি সর্বদা অবজেক্টের অন্য তালিকা থেকে টোডেওয়ারিয়ান () ব্যবহার করতে পারেন।

সুতরাং, আপনার ক্ষেত্রে, আপনি এই জাতীয় কিছু করবেন:

Dictionary<string, string> dic = new Dictionary<string, string>();
dic = SomeList.ToDictionary(x => x.Attribute1, x => x.Attribute2);

5
আপনার একটি নতুন অভিধান তৈরি করার দরকার নেই, কেবল লিখুনDictionary<string, string> dic = SomeList.ToDictionary...
Panagiotis Kanavos

1

আপনি যদি জানেন যে আপনার কাছে সদৃশ কী নেই তবে আপনি এটি করতে পারেন:

dic = dic.Union(MethodThatReturnAnotherDic()).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

যদি কোনও সদৃশ কী / মান জোড় থাকে তবে এটি একটি ব্যতিক্রম ছুঁড়ে দেবে।

আমি জানি না কেন এটি কাঠামোর মধ্যে নেই; হতে হবে. কোনও অনিশ্চয়তা নেই; শুধু একটি ব্যতিক্রম নিক্ষেপ। এই কোডের ক্ষেত্রে এটি একটি ব্যতিক্রম ছুঁড়ে ফেলেছে।


যদি মূল অভিধানটি ব্যবহার করে তৈরি করা হত var caseInsensitiveDictionary = new Dictionary<string, int>( StringComparer.OrdinalIgnoreCase);?
এমজেউইলস

1

এই জাতীয় এক্সটেনশন পদ্ধতিটি নির্দ্বিধায় ব্যবহার করুন:

public static Dictionary<T, U> AddRange<T, U>(this Dictionary<T, U> destination, Dictionary<T, U> source)
{
  if (destination == null) destination = new Dictionary<T, U>();
  foreach (var e in source)
    destination.Add(e.Key, e.Value);
  return destination;
}

0

এখানে সি # 7 ভ্যালুটিপলস (টিপল লিটারাল) ব্যবহার করে একটি বিকল্প সমাধান দেওয়া হচ্ছে

public static class DictionaryExtensions
{
    public static Dictionary<TKey, TValue> AddRange<TKey, TValue>(this Dictionary<TKey, TValue> source,  IEnumerable<ValueTuple<TKey, TValue>> kvps)
    {
        foreach (var kvp in kvps)
            source.Add(kvp.Item1, kvp.Item2);

        return source;
    }

    public static void AddTo<TKey, TValue>(this IEnumerable<ValueTuple<TKey, TValue>> source, Dictionary<TKey, TValue> target)
    {
        target.AddRange(source);
    }
}

যেমন ব্যবহার করা হয়

segments
    .Zip(values, (s, v) => (s.AsSpan().StartsWith("{") ? s.Trim('{', '}') : null, v))
    .Where(zip => zip.Item1 != null)
    .AddTo(queryParams);

0

যেমনটি অন্যরা উল্লেখ করেছেন, Dictionary<TKey,TVal>.AddRangeবাস্তবায়িত না হওয়ার কারণ হ'ল কারণ যেখানে আপনার নকল রয়েছে সেখানে বিভিন্ন পদ্ধতিতে আপনি হ্যান্ডেল করতে চাইতে পারেন। এই ক্ষেত্রে দেখা যায় Collectionবা এই ধরনের যেমন ইন্টারফেসগুলি IDictionary<TKey,TVal>, ICollection<T>ইত্যাদি

List<T>এটি কেবলমাত্র প্রয়োগ করে, এবং আপনি লক্ষ করবেন যে IList<T>ইন্টারফেসটি একই কারণে নয়: কোনও সংকলনে মানের একটি সীমা যুক্ত করার সময় প্রত্যাশিত আচরণ প্রসঙ্গের উপর নির্ভর করে ব্যাপকভাবে পরিবর্তিত হতে পারে।

আপনার প্রশ্নের প্রসঙ্গে পরামর্শ দেয় আপনি নকলগুলি সম্পর্কে উদ্বিগ্ন নন, এমন ক্ষেত্রে আপনার কাছে লিনক ব্যবহার করে একটি সহজ অনিলিঞ্জার বিকল্প রয়েছে:

MethodThatReturnAnotherDic().ToList.ForEach(kvp => dic.Add(kvp.Key, kvp.Value));
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.