শিরোনাম যথেষ্ট বেসিক, আমি কেন করতে পারি না:
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.AddRange(MethodThatReturnAnotherDic());
শিরোনাম যথেষ্ট বেসিক, আমি কেন করতে পারি না:
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.AddRange(MethodThatReturnAnotherDic());
উত্তর:
মূল প্রশ্নের একটি মন্তব্য এটির বেশ ভাল যোগ করে:
কারণ এই বৈশিষ্ট্যটি ডিজাইন, নির্দিষ্ট, প্রয়োগ, পরীক্ষিত, নথিভুক্ত ও শিপড কেউই করেনি। - @ গাবে মোথার্ট
কেন? ঠিক আছে, সম্ভবত কারণ মার্জিং অভিধানগুলির আচরণের ফ্রেমওয়ার্ক নির্দেশিকাগুলির সাথে মানানসই এমন পদ্ধতিতে যুক্তিযুক্ত হতে পারে না।
AddRange
তথ্যের পরিসীমা সদৃশ এন্ট্রিগুলির জন্য মঞ্জুরি দেওয়ার কারণে কোনও সীমাবদ্ধ কোনও ধারক কনটেইনারটির কোনও অর্থ হয় না বলে উপস্থিত নেই। যেমন আপনার যদি IEnumerable<KeyValuePair<K,T>>
সংগ্রহ থাকে তবে সদৃশ এন্ট্রি থেকে রক্ষা না করে।
কী-মান জোড়ের সংকলন যুক্ত করতে, এমনকি দুটি অভিধান একত্রিত করার আচরণটি সরাসরি-এগিয়ে। একাধিক সদৃশ এন্ট্রিগুলি কীভাবে মোকাবেলা করা উচিত তা আচরণ নয়।
কোনও সদৃশ নিয়ে কাজ করার সময় পদ্ধতির আচরণ কী হওয়া উচিত?
আমি ভাবতে পারি এমন কমপক্ষে তিনটি সমাধান রয়েছে:
যখন একটি ব্যতিক্রম নিক্ষেপ করা হয়, মূল অভিধানের অবস্থাটি কী হওয়া উচিত?
Add
প্রায় সর্বদা একটি পারমাণবিক অপারেশন হিসাবে প্রয়োগ করা হয়: এটি সংগ্রহের সাফল্য এবং আপডেট করে বা ব্যর্থ হয় এবং সংগ্রহের অবস্থা অপরিবর্তিত থাকে। AddRange
সদৃশ ত্রুটির কারণে যেমন ব্যর্থ হতে পারে, তার আচরণের সাথে সামঞ্জস্য রাখার উপায় Add
হ'ল কোনও অনুলিপিতে একটি ব্যতিক্রম ছড়িয়ে এটিকে পারমাণবিক করা এবং মূল অভিধানের অবস্থাটি অপরিবর্তিত হিসাবে রেখে দেওয়া।
একটি API গ্রাহক হিসাবে, পুনরাবৃত্তভাবে সদৃশ উপাদানগুলি সরিয়ে ফেলা বিরক্তিকর হবে, যার দ্বারা বোঝা যায় যে সমস্ত ডুপ্লিকেট মান AddRange
রয়েছে এমন একক ব্যতিক্রম ছড়িয়ে দেওয়া উচিত ।
পছন্দটি তখন এতে সিদ্ধ হয়:
উভয় ব্যবহারের ক্ষেত্রে সমর্থন করার পক্ষে যুক্তি রয়েছে। এটি করতে, আপনি কি IgnoreDuplicates
স্বাক্ষরে একটি পতাকা যুক্ত করবেন?
IgnoreDuplicates
পতাকা (যখন সত্যতে সেট) ও অন্তর্নিহিত বাস্তবায়ন যেমন, আপ উল্লেখযোগ্য গতি প্রদান করবে would ডুপ্লিকেট পরীক্ষণ কোড বাইপাস।
সুতরাং, এখন আপনার কাছে একটি পতাকা রয়েছে যা AddRange
উভয় ক্ষেত্রেই সমর্থন করতে সহায়তা করে তবে এর একটি অনিবন্ধিত পার্শ্ব প্রতিক্রিয়া রয়েছে (যা এমন কিছু যা ফ্রেমওয়ার্ক ডিজাইনাররা এড়াতে সত্যিই কঠোর পরিশ্রম করেছিল)।
সারসংক্ষেপ
সদৃশদের সাথে ডিল করার ক্ষেত্রে যখন কোনও স্পষ্ট, সামঞ্জস্যপূর্ণ এবং প্রত্যাশিত আচরণ নেই, সেহেতু তাদের সকলের সাথে একত্রে আচরণ করা এবং শুরু করার পদ্ধতিটি সরবরাহ না করা সহজ।
আপনি যদি নিজেকে ক্রমাগত অভিধানগুলিকে মার্জ করতে দেখেন তবে আপনি অবশ্যই অভিধানগুলিকে মার্জ করার জন্য আপনার নিজের এক্সটেনশন পদ্ধতিটি লিখতে পারেন যা আপনার অ্যাপ্লিকেশন (গুলি) এর জন্য কাজ করে এমনভাবে আচরণ করবে।
AddMultiple
AddRange
এর বাস্তবায়নটি উইঙ্কি হতে চলেছে তা নির্বিশেষে ভিন্ন : আপনি কি সমস্ত ডুপ্লিকেট কীগুলির একটি অ্যারে দিয়ে একটি ব্যতিক্রম ছুঁড়েন ? অথবা আপনি যে প্রথম ডুপ্লিকেট কীটির মুখোমুখি হয়েছেন তাতে কি ব্যতিক্রম ছুঁড়ে মারছেন? যদি কোনও ব্যতিক্রম ছুঁড়ে দেওয়া হয় তবে অভিধানের অবস্থাটি কী হওয়া উচিত? প্রিস্টাইন, বা সমস্ত কী কী সফল হয়েছিল?
Add
- হয় প্রতিটি মোড়ানো Add
একটি try...catch
এবং অনুরূপ ধরতে উপায় যে; বা সূচক ব্যবহার করুন এবং পরবর্তী মানটি দিয়ে প্রথম মানটি ওভাররাইট করুন; বা প্রিমিটিভলি ContainsKey
চেষ্টা করার আগে ব্যবহার করে পরীক্ষা করুন Add
, এভাবে মূল মান সংরক্ষণ করা। যদি কাঠামোর কোনও AddRange
বা AddMultiple
পদ্ধতি থাকে, তবে যা ঘটেছিল তার যোগাযোগের একমাত্র সহজ উপায়টি ব্যতিক্রমের মধ্য দিয়ে ছিল এবং জড়িত হ্যান্ডলিং এবং পুনরুদ্ধার কোনও কম জটিল হবে না।
আমি কিছু সমাধান পেয়েছি:
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)...
ToList()
ভাল সমাধান নয় তাই আমি কোডটি পরিবর্তন করেছি। আপনি try { mainDic.AddRange(addDic); } catch { do something }
যদি তৃতীয় পদ্ধতির বিষয়ে নিশ্চিত না হন তবে আপনি ব্যবহার করতে পারেন । দ্বিতীয় পদ্ধতিটি নিখুঁতভাবে কাজ করে।
যদি কেউ এই প্রশ্নটি আমার মতো করে আসে - তবে আইননামারেবল এক্সটেনশন পদ্ধতি ব্যবহার করে "অ্যাডরেঞ্জ" অর্জন করা সম্ভব:
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
না করে ?
var combined = dict1.Concat(dict2).GroupBy(kvp => kvp.Key, dict1.Comparer).ToDictionary(grp => grp.Key, grp=> grp.First(), dict1.Comparer);
আমার অনুমানটি যা হয়েছে তা হিসাবে ব্যবহারকারীর যথাযথ আউটপুটের অভাব। আপনার অভিধানে পুনরাবৃত্তি কীগুলি থাকতে পারে না, যেখানে কিছু কী ছেদ করে যেখানে আপনি দুটি অভিধান মার্জ করবেন তা কীভাবে পরিচালনা করবেন? নিশ্চিতভাবে আপনি বলতে পারেন: "আমি যত্ন করি না" তবে এটি পুনরাবৃত্তি কীগুলির জন্য মিথ্যা / ফেরত দেওয়ার ব্যপারটি ভেঙে চলেছে breaking
Add
হয় তার থেকে এটি কীভাবে আলাদা, তা ছাড়াও এটি একাধিকবার ঘটতে পারে। এটি একই ArgumentException
যে নিক্ষেপ করবে Add
, অবশ্যই?
NamedElementException
??), হয় পরিবর্তে নিক্ষেপ করা হয় বা একটি আর্গুমেন্টএক্সসেপশনটির অভ্যন্তরীণ ধারণা হিসাবে চিহ্নিত হয় যা বিরোধিত নামযুক্ত উপাদানকে নির্দিষ্ট করে ... কয়েকটি ভিন্ন বিকল্প, আমি বলব
আপনি এটি করতে পারে
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>>
MethodThatReturnAnotherDic
। এটি ওপি থেকে আসে। প্রশ্ন এবং আমার উত্তর আবার পর্যালোচনা করুন।
আপনি যদি ডাব্লু / একটি নতুন অভিধান (এবং আপনার কাছে বিদ্যমান সারিগুলি হারাতে না পারে) ডিল করে থাকেন তবে আপনি সর্বদা অবজেক্টের অন্য তালিকা থেকে টোডেওয়ারিয়ান () ব্যবহার করতে পারেন।
সুতরাং, আপনার ক্ষেত্রে, আপনি এই জাতীয় কিছু করবেন:
Dictionary<string, string> dic = new Dictionary<string, string>();
dic = SomeList.ToDictionary(x => x.Attribute1, x => x.Attribute2);
Dictionary<string, string> dic = SomeList.ToDictionary...
আপনি যদি জানেন যে আপনার কাছে সদৃশ কী নেই তবে আপনি এটি করতে পারেন:
dic = dic.Union(MethodThatReturnAnotherDic()).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
যদি কোনও সদৃশ কী / মান জোড় থাকে তবে এটি একটি ব্যতিক্রম ছুঁড়ে দেবে।
আমি জানি না কেন এটি কাঠামোর মধ্যে নেই; হতে হবে. কোনও অনিশ্চয়তা নেই; শুধু একটি ব্যতিক্রম নিক্ষেপ। এই কোডের ক্ষেত্রে এটি একটি ব্যতিক্রম ছুঁড়ে ফেলেছে।
var caseInsensitiveDictionary = new Dictionary<string, int>( StringComparer.OrdinalIgnoreCase);
?
এই জাতীয় এক্সটেনশন পদ্ধতিটি নির্দ্বিধায় ব্যবহার করুন:
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;
}
এখানে সি # 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);
যেমনটি অন্যরা উল্লেখ করেছেন, Dictionary<TKey,TVal>.AddRange
বাস্তবায়িত না হওয়ার কারণ হ'ল কারণ যেখানে আপনার নকল রয়েছে সেখানে বিভিন্ন পদ্ধতিতে আপনি হ্যান্ডেল করতে চাইতে পারেন। এই ক্ষেত্রে দেখা যায় Collection
বা এই ধরনের যেমন ইন্টারফেসগুলি IDictionary<TKey,TVal>
, ICollection<T>
ইত্যাদি
List<T>
এটি কেবলমাত্র প্রয়োগ করে, এবং আপনি লক্ষ করবেন যে IList<T>
ইন্টারফেসটি একই কারণে নয়: কোনও সংকলনে মানের একটি সীমা যুক্ত করার সময় প্রত্যাশিত আচরণ প্রসঙ্গের উপর নির্ভর করে ব্যাপকভাবে পরিবর্তিত হতে পারে।
আপনার প্রশ্নের প্রসঙ্গে পরামর্শ দেয় আপনি নকলগুলি সম্পর্কে উদ্বিগ্ন নন, এমন ক্ষেত্রে আপনার কাছে লিনক ব্যবহার করে একটি সহজ অনিলিঞ্জার বিকল্প রয়েছে:
MethodThatReturnAnotherDic().ToList.ForEach(kvp => dic.Add(kvp.Key, kvp.Value));