.NET Framework
शब्दकोश
खोज…
एक शब्दकोश की गणना
आप डिक्शनरी में 3 में से किसी एक तरीके से गणना कर सकते हैं:
KeyValue जोड़े का उपयोग करना
Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(KeyValuePair<int, string> kvp in dict)
{
Console.WriteLine("Key : " + kvp.Key.ToString() + ", Value : " + kvp.Value);
}
कुंजी का उपयोग करना
Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(int key in dict.Keys)
{
Console.WriteLine("Key : " + key.ToString() + ", Value : " + dict[key]);
}
मूल्यों का उपयोग करना
Dictionary<int, string> dict = new Dictionary<int, string>();
foreach(string s in dict.Values)
{
Console.WriteLine("Value : " + s);
}
एक संग्रह शुरुआती के साथ एक शब्दकोश की शुरुआत
// Translates to `dict.Add(1, "First")` etc.
var dict = new Dictionary<int, string>()
{
{ 1, "First" },
{ 2, "Second" },
{ 3, "Third" }
};
// Translates to `dict[1] = "First"` etc.
// Works in C# 6.0.
var dict = new Dictionary<int, string>()
{
[1] = "First",
[2] = "Second",
[3] = "Third"
};
एक शब्दकोश में जोड़ना
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "First");
dict.Add(2, "Second");
// To safely add items (check to ensure item does not already exist - would throw)
if(!dict.ContainsKey(3))
{
dict.Add(3, "Third");
}
वैकल्पिक रूप से उन्हें एक अनुक्रमणिका के माध्यम से जोड़ा / सेट किया जा सकता है। (एक अनुक्रमणिका आंतरिक रूप से एक संपत्ति की तरह दिखती है, जिसमें एक गेट और सेट होता है, लेकिन किसी भी प्रकार का पैरामीटर लेता है जो कोष्ठक के बीच निर्दिष्ट होता है):
Dictionary<int, string> dict = new Dictionary<int, string>();
dict[1] = "First";
dict[2] = "Second";
dict[3] = "Third";
Add
मेथड के विपरीत, जो एक अपवाद को फेंकता है, यदि कोई कुंजी पहले से ही शब्दकोश में समाहित है, तो इंडेक्सर मौजूदा मान को बदल देता है।
थ्रेड-सेफ डिक्शनरी के लिए ConcurrentDictionary<TKey, TValue>
:
var dict = new ConcurrentDictionary<int, string>();
dict.AddOrUpdate(1, "First", (oldKey, oldValue) => "First");
एक शब्दकोश से एक मूल्य प्राप्त करना
इस सेटअप कोड को देखते हुए:
var dict = new Dictionary<int, string>()
{
{ 1, "First" },
{ 2, "Second" },
{ 3, "Third" }
};
आप कुंजी 1 के साथ प्रविष्टि के लिए मान पढ़ना चाह सकते हैं। यदि कुंजी मौजूद नहीं है, तो मान KeyNotFoundException
को फेंक KeyNotFoundException
, इसलिए आप इसके लिए पहले ContainsKey
जांच कर सकते हैं:
if (dict.ContainsKey(1))
Console.WriteLine(dict[1]);
इसका एक नुकसान है: आप अपने शब्दकोश के माध्यम से दो बार खोज करेंगे (एक बार अस्तित्व की जांच करने के लिए और एक मूल्य को पढ़ने के लिए)। एक बड़े शब्दकोश के लिए यह प्रदर्शन को प्रभावित कर सकता है। सौभाग्य से दोनों ऑपरेशन एक साथ किए जा सकते हैं:
string value;
if (dict.TryGetValue(1, out value))
Console.WriteLine(value);
एक शब्दकोश बनाओ केस-इन्सेंसविट कुंजियों के साथ।
var MyDict = new Dictionary<string,T>(StringComparison.InvariantCultureIgnoreCase)
ConcurrentDictionary (.NET 4.0 से)
कुंजी / मान जोड़े के एक थ्रेड-सुरक्षित संग्रह का प्रतिनिधित्व करता है जिसे कई धागे द्वारा समवर्ती रूप से एक्सेस किया जा सकता है।
एक उदाहरण बनाना
एक उदाहरण बनाना बहुत ही उसी तरह काम करता है जैसे Dictionary<TKey, TValue>
साथ Dictionary<TKey, TValue>
, उदा:
var dict = new ConcurrentDictionary<int, string>();
जोड़ना या अद्यतन करना
आप आश्चर्यचकित हो सकते हैं, कि कोई Add
विधि नहीं है, लेकिन इसके बजाय 2 अधिभार के साथ AddOrUpdate
:
(1) AddOrUpdate(TKey key, TValue, Func<TKey, TValue, TValue> addValue)
- यदि कुंजी पहले से मौजूद नहीं है, तो कुंजी / मान युग्म जोड़ता है, या यदि कुंजी निर्दिष्ट करता है, तो निर्दिष्ट फ़ंक्शन का उपयोग करके कुंजी / मान युग्म को अद्यतन करता है। पहले से ही मौजूद है।
(2) AddOrUpdate(TKey key, Func<TKey, TValue> addValue, Func<TKey, TValue, TValue> updateValueFactory)
- यदि कुंजी पहले से मौजूद नहीं है, तो कुंजी / मान युग्म जोड़ने के लिए निर्दिष्ट फ़ंक्शन का उपयोग करता है या यदि कुंजी पहले से मौजूद है, तो कुंजी / मान युग्म को अपडेट करें।
किसी मूल्य को जोड़ना या अपडेट करना, चाहे वह पहले से मौजूद कुंजी (1) के लिए मौजूद हो, कोई फर्क नहीं पड़ता:
string addedValue = dict.AddOrUpdate(1, "First", (updateKey, valueOld) => "First");
मूल्य जोड़ना या अपडेट करना, लेकिन अब पिछले मूल्य (1) के आधार पर, अपडेट में मूल्य में फेरबदल करना:
string addedValue2 = dict.AddOrUpdate(1, "First", (updateKey, valueOld) => $"{valueOld} Updated");
अधिभार (2) का उपयोग करके हम किसी कारखाने का उपयोग करके नए मूल्य भी जोड़ सकते हैं:
string addedValue3 = dict.AddOrUpdate(1, (key) => key == 1 ? "First" : "Not First", (updateKey, valueOld) => $"{valueOld} Updated");
मूल्य प्राप्त करना
एक मूल्य प्राप्त करना Dictionary<TKey,TValue>
:
string value = null;
bool success = dict.TryGetValue(1, out value);
मान प्राप्त करना या जोड़ना
दो मेयोड अधिभार हैं, जो थ्रेड-सुरक्षित तरीके से एक मूल्य प्राप्त करेंगे या जोड़ेंगे ।
यदि कुंजी मौजूद नहीं है, तो कुंजी 2 के साथ मान प्राप्त करें, या "दूसरा" मान जोड़ें:
string theValue = dict.GetOrAdd(2, "Second");
यदि मान मौजूद नहीं है, तो मूल्य जोड़ने के लिए एक कारखाने का उपयोग करना:
string theValue2 = dict.GetOrAdd(2, (key) => key == 2 ? "Second" : "Not Second." );
IEnumerable to Dictionary (3.5 .NET 3.5)
एक IEnumerable <T> से एक शब्दकोश <TKey, TValue> एक शब्दकोश बनाएँ:
using System;
using System.Collections.Generic;
using System.Linq;
public class Fruits
{
public int Id { get; set; }
public string Name { get; set; }
}
var fruits = new[]
{
new Fruits { Id = 8 , Name = "Apple" },
new Fruits { Id = 3 , Name = "Banana" },
new Fruits { Id = 7 , Name = "Mango" },
};
// Dictionary<int, string> key value
var dictionary = fruits.ToDictionary(x => x.Id, x => x.Name);
एक शब्दकोश से हटाना
इस सेटअप कोड को देखते हुए:
var dict = new Dictionary<int, string>()
{
{ 1, "First" },
{ 2, "Second" },
{ 3, "Third" }
};
किसी कुंजी और उसके संबद्ध मान को निकालने के लिए Remove
विधि का उपयोग करें।
bool wasRemoved = dict.Remove(2);
इस कोड को निष्पादित करने से कुंजी 2
को हटा दिया जाता है और यह शब्दकोश से मूल्य होता है। Remove
एक बूलियन मान दर्शाता है कि क्या निर्दिष्ट कुंजी पाया गया था और शब्दकोश से हटा दिया गया था। यदि कुंजी शब्दकोष में मौजूद नहीं है, तो शब्दकोश से कुछ भी नहीं हटाया जाता है, और झूठी लौटा दी जाती है (कोई अपवाद नहीं फेंका जाता है)।
null
की कुंजी के लिए मान सेट करके एक कुंजी को हटाने की कोशिश करना गलत है।
dict[2] = null; // WRONG WAY TO REMOVE!
इससे चाबी नहीं निकलेगी। यह बस पिछले मान को null
मान से बदल देगा।
शब्दकोश से सभी कुंजी और मान निकालने के लिए, Clear
विधि का उपयोग करें।
dict.Clear();
Clear
करने के बाद शब्दकोश की Count
0 होगी, लेकिन आंतरिक क्षमता अपरिवर्तित रहती है।
ContainsKey (TKey)
यह जांचने के लिए कि क्या किसी Dictionary
की कोई कुंजी है, आप ContainsKey(TKey)
विधि को कॉल कर सकते हैं और TKey
प्रकार की कुंजी प्रदान कर सकते हैं। शब्दकोश में कुंजी मौजूद होने पर विधि एक bool
मान देता है। नमूने के लिए:
var dictionary = new Dictionary<string, Customer>()
{
{"F1", new Customer() { FirstName = "Felipe", ... } },
{"C2", new Customer() { FirstName = "Carl", ... } },
{"J7", new Customer() { FirstName = "John", ... } },
{"M5", new Customer() { FirstName = "Mary", ... } },
};
और जाँच करें कि क्या C2
डिक्शनरी में मौजूद है:
if (dictionary.ContainsKey("C2"))
{
// exists
}
ContainsKey पद्धति जेनेरिक संस्करण Dictionary<TKey, TValue>
।
शब्दकोश सूची के लिए
KeyValuePair की सूची बनाना:
Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<KeyValuePair<int, int>> list = new List<KeyValuePair<int, int>>();
list.AddRange(dictionary);
कुंजियों की सूची बनाना:
Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<int> list = new List<int>();
list.AddRange(dictionary.Keys);
मूल्यों की सूची बनाना:
Dictionary<int, int> dictionary = new Dictionary<int, int>();
List<int> list = new List<int>();
list.AddRange(dictionary.Values);
Lazy'1 के साथ संवर्धित समवर्ती छायांकित संगणना कम कर देता है
मुसीबत
जब यह तुरंत कैश से मौजूदा कुंजियों की वापसी की बात करता है, तो समवर्ती छायांकन चमकता है, ज्यादातर लॉक मुक्त होता है, और एक दानेदार स्तर पर होता है। लेकिन क्या होगा यदि वस्तु निर्माण वास्तव में महंगा है, संदर्भ स्विचिंग की लागत को पछाड़ कर, और कुछ कैश मिस हो जाए?
यदि एक ही कुंजी को कई थ्रेड्स से अनुरोध किया गया है, तो टकराए गए संचालन से उत्पन्न वस्तुओं में से एक को अंततः संग्रह में जोड़ा जाएगा, और अन्य को दूर फेंक दिया जाएगा, सीपीयू संसाधन को बर्बाद करके वस्तु और मेमोरी संसाधन को अस्थायी रूप से संग्रहीत करने के लिए । अन्य संसाधनों को भी बर्बाद किया जा सकता है। यह वास्तव में बुरा है।
समाधान
हम ConcurrentDictionary<TKey, TValue>
को Lazy<TValue>
साथ जोड़ सकते हैं। विचार यह है कि समवर्ती छाया GetOrAdd विधि केवल उस मूल्य को वापस कर सकती है जो वास्तव में संग्रह में जोड़ा गया था। आलसी वस्तुओं को इस मामले में भी बर्बाद किया जा सकता है, लेकिन यह ज्यादा समस्या नहीं है, क्योंकि आलसी वस्तु अपने आप में अपेक्षाकृत सस्ती है। हारने वाले आलसी की मूल्य संपत्ति का अनुरोध कभी नहीं किया जाता है, क्योंकि हम केवल उस संग्रह के मूल्य संपत्ति का अनुरोध करने के लिए स्मार्ट हैं जो संग्रह में जोड़ा गया है - एक गेटऑर्ड विधि से लौटा है:
public static class ConcurrentDictionaryExtensions
{
public static TValue GetOrCreateLazy<TKey, TValue>(
this ConcurrentDictionary<TKey, Lazy<TValue>> d,
TKey key,
Func<TKey, TValue> factory)
{
return
d.GetOrAdd(
key,
key1 =>
new Lazy<TValue>(() => factory(key1),
LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}
}
XmlSerializer ऑब्जेक्ट्स का कैशिंग विशेष रूप से महंगा हो सकता है, और एप्लिकेशन स्टार्टअप पर बहुत अधिक विवाद भी है। और इसके अलावा भी बहुत कुछ है: यदि वे कस्टम सीरियलाइज़र हैं, तो बाकी प्रक्रिया जीवनचक्र के लिए मेमोरी लीक भी होगी। इस मामले में समवर्ती ढाल का एकमात्र लाभ यह है कि शेष प्रक्रिया जीवनचक्र के लिए कोई लॉक नहीं होगा, लेकिन एप्लिकेशन स्टार्टअप और मेमोरी उपयोग अस्वीकार्य होगा। यह हमारे समवर्ती के लिए एक नौकरी है, जो आलसी के साथ संवर्धित है:
private ConcurrentDictionary<Type, Lazy<XmlSerializer>> _serializers =
new ConcurrentDictionary<Type, Lazy<XmlSerializer>>();
public XmlSerializer GetSerialier(Type t)
{
return _serializers.GetOrCreateLazy(t, BuildSerializer);
}
private XmlSerializer BuildSerializer(Type t)
{
throw new NotImplementedException("and this is a homework");
}