शीर्षक पर्याप्त बुनियादी है, मैं क्यों नहीं कर सकता:
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यह भी होगा कि किसी भी डुप्लिकेट पर एक अपवाद को फेंककर इसे परमाणु बना दिया जाए, और मूल शब्दकोश की स्थिति को अपरिवर्तित छोड़ दें।
एपीआई उपभोक्ता के रूप में, डुप्लिकेट तत्वों को पुनरावृत्त करने के लिए इसे थकाऊ AddRangeहोना चाहिए , जिसका अर्थ है कि एक एकल अपवाद को फेंकना चाहिए जिसमें सभी डुप्लिकेट मान शामिल हैं।
चुनाव तब उबलता है:
दोनों उपयोग मामलों का समर्थन करने के लिए तर्क हैं। ऐसा करने के लिए, क्या आप IgnoreDuplicatesहस्ताक्षर में एक झंडा जोड़ते हैं ?
IgnoreDuplicatesध्वज (जब सही पर सेट) भी अंतर्निहित कार्यान्वयन के रूप में, एक महत्वपूर्ण गति प्रदान करेगा होगा डुप्लिकेट जांच के लिए कोड बाईपास।
तो अब, आपके पास एक ध्वज है जो 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 }यदि आप तीसरी विधि के लिए सुनिश्चित नहीं हैं, तो आप इसका उपयोग कर सकते हैं । दूसरी विधि पूरी तरह से काम करती है।
यदि कोई व्यक्ति स्वयं की तरह इस प्रश्न पर आता है - IEnumerable एक्सटेंशन विधियों का उपयोग करके "AddRange" को प्राप्त करना संभव है:
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);
मेरा अनुमान उपयोगकर्ता को उचित आउटपुट का अभाव है जैसा कि हुआ था। जैसा कि आप एक शब्दकोश में कुंजियों को दोहरा नहीं सकते हैं, तो आप दो शब्दकोशों को मर्ज करने से कैसे निपटेंगे जहां कुछ कुंजियाँ मिलती हैं? सुनिश्चित करें कि आप कह सकते हैं: "मुझे परवाह नहीं है" लेकिन यह झूठे / वापसी की परंपरा को तोड़ रहा है और चाबियों को दोहराने के लिए एक अपवाद फेंक रहा है।
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। यह ओपी से आता है। कृपया प्रश्न और मेरे उत्तर की फिर से समीक्षा करें।
यदि आप w / एक नया शब्दकोश काम कर रहे हैं (और आपके पास खोने के लिए मौजूदा पंक्तियाँ नहीं हैं), तो आप हमेशा ऑब्जेक्ट्स की एक अन्य सूची से To मंदार () का उपयोग कर सकते हैं।
तो, आपके मामले में, आप कुछ इस तरह से करेंगे:
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;
}
यहाँ c # 7 ValueTuples (tuple literals) का उपयोग कर एक वैकल्पिक समाधान दिया गया है
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));