c# - एक शब्दकोश पर फिर से शुरू करने का सबसे अच्छा तरीका क्या है?




dictionary loops (21)

मैंने सी # में एक शब्दकोश में फिर से शुरू करने के कुछ अलग तरीके देखे हैं। क्या कोई मानक तरीका है?


Answers

कुछ मामलों में आपको काउंटर की आवश्यकता हो सकती है जो फॉर-लूप कार्यान्वयन द्वारा प्रदान की जा सकती है। इसके लिए, LINQ ElementAt प्रदान करता है जो निम्न को सक्षम बनाता है:

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}

.NET Framework 4.7 कोई अपघटन का उपयोग कर सकता है

var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
    Console.WriteLine(fruit + ": " + number);
}

इस कोड को कम C # संस्करणों पर काम करने के लिए, System.ValueTuple NuGet package जोड़ें और कहीं लिखें

public static class MyExtensions
{
    public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
        out T1 key, out T2 value)
    {
        key = tuple.Key;
        value = tuple.Value;
    }
}

मैं कहूंगा कि foreach मानक तरीका है, हालांकि यह स्पष्ट रूप से उस पर निर्भर करता है जो आप खोज रहे हैं

foreach(var kvp in my_dictionary) {
  ...
}

क्या आप यही खोज रहे हैं?


यदि आप सी # में जेनेरिक डिक्शनरी का उपयोग करने की कोशिश कर रहे हैं, तो आप किसी अन्य भाषा में एक एसोसिएटिव सरणी का उपयोग करेंगे:

foreach(var item in myDictionary)
{
  foo(item.Key);
  bar(item.Value);
}

या, यदि आपको केवल चाबियों के संग्रह पर पुन: प्रयास करने की आवश्यकता है, तो उपयोग करें

foreach(var item in myDictionary.Keys)
{
  foo(item);
}

और आखिरकार, यदि आप केवल मूल्यों में रूचि रखते हैं:

foreach(var item in myDictionary.Values)
{
  foo(item);
}

(ध्यान दें कि var कीवर्ड एक वैकल्पिक सी # 3.0 और ऊपर की सुविधा है, आप यहां अपनी चाबियों / मानों के सटीक प्रकार का भी उपयोग कर सकते हैं)


उच्चतम रैंकिंग पदों के अलावा जहां उपयोग के बीच चर्चा है

foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

या

foreach(var entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

सबसे पूरा निम्नलिखित है क्योंकि आप प्रारंभिक से शब्दकोश प्रकार देख सकते हैं, केवीपी KeyValuePair है

var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x

foreach(var kvp in myDictionary)//iterate over dictionary
{
    // do something with kvp.Value or kvp.Key
}

कभी-कभी यदि आपको केवल मूल्यों की गणना करने की आवश्यकता होती है, तो शब्दकोश के मूल्य संग्रह का उपयोग करें:

foreach(var value in dictionary.Values)
{
    // do something with entry.Value only
}

इस पोस्ट द्वारा रिपोर्ट किया गया है जिसमें कहा गया है कि यह सबसे तेज़ तरीका है: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html


मैं इस प्रश्न की सराहना करता हूं कि पहले से ही बहुत सारे प्रतिक्रियाएं हैं लेकिन मैं थोड़ा सा शोध करना चाहता हूं।

किसी सरणी की तरह किसी चीज़ पर पुनरावर्तित होने की तुलना में एक शब्दकोश पर इटरेट करना धीमा हो सकता है। मेरे परीक्षणों में एक सरणी पर एक पुनरावृत्ति 0.015003 सेकंड ले लिया गया जबकि एक शब्दकोश (एक ही संख्या में तत्वों के साथ) पर एक पुनरावृत्ति 0.0365073 सेकंड ले गया जो कि 2.4 गुना लंबा है! हालांकि मैंने बहुत बड़ा अंतर देखा है। तुलना के लिए एक सूची 0.00215043 सेकंड के बीच कहीं थी।

हालांकि, यह सेब और संतरे की तुलना की तरह है। मेरा मुद्दा यह है कि शब्दकोशों पर पुनरावृत्ति धीमी है।

शब्दकोश लुकअप के लिए अनुकूलित किए गए हैं, इसलिए इसे ध्यान में रखते हुए मैंने दो विधियां बनाई हैं। एक बस एक foreach करता है, दूसरा चाबियाँ फिर से दिखता है।

public static string Normal(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var kvp in dictionary)
    {
        value = kvp.Value;
        count++;
    }

    return "Normal";
}

यह एक कुंजी को लोड करता है और इसके बजाय पुनरावृत्त करता है (मैंने चाबियों को स्ट्रिंग में खींचने का भी प्रयास किया [] लेकिन अंतर नगण्य था।

public static string Keys(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var key in dictionary.Keys)
    {
        value = dictionary[key];
        count++;
    }

    return "Keys";
}

इस उदाहरण के साथ सामान्य foreach परीक्षण 0.0310062 लिया और कुंजी संस्करण 0.2205441 लिया। सभी कुंजियों को लोड करना और सभी लुकअप पर पुनरावृत्ति स्पष्ट रूप से बहुत धीमी है!

अंतिम परीक्षण के लिए मैंने यह देखने के लिए दस बार अपना पुनरावृत्ति किया है कि क्या चाबियों का उपयोग करने के कोई लाभ हैं (इस बिंदु से मैं केवल उत्सुक था):

यहां रनटेस्ट विधि है यदि इससे आपको यह देखने में मदद मिलती है कि क्या हो रहा है।

private static string RunTest<T>(T dictionary, Func<T, string> function)
{            
    DateTime start = DateTime.Now;
    string name = null;
    for (int i = 0; i < 10; i++)
    {
        name = function(dictionary);
    }
    DateTime end = DateTime.Now;
    var duration = end.Subtract(start);
    return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
}

यहां सामान्य foreach रन 0.2820564 सेकंड (एक ही पुनरावृत्ति से लगभग दस गुना लंबा लिया - जैसा कि आप उम्मीद करेंगे)। चाबियों पर पुनरावृत्ति 2.224 9 44 9 सेकेंड ले लिया।

जोड़ने के लिए संपादित: कुछ अन्य उत्तरों को पढ़ने से मुझे सवाल आया कि अगर मैं शब्दकोश के बजाय शब्दकोश का उपयोग करता तो क्या होगा। इस उदाहरण में सरणी ने 0.0120024 सेकंड, सूची 0.0185037 सेकंड और शब्दकोश 0.04650 9 3 सेकंड लिया। यह अपेक्षा करना उचित है कि डेटा प्रकार इस बात पर एक फर्क पड़ता है कि शब्दकोश कितना धीमा है।

मेरे निष्कर्ष क्या हैं ?

  • यदि आप कर सकते हैं तो एक शब्दकोश पर पुनरावृत्ति से बचें, वे एक ही डेटा के साथ एक सरणी पर फिर से चलने से काफी धीमे हैं।
  • यदि आप एक शब्दकोश पर फिर से शुरू करना चुनते हैं तो बहुत चालाक होने की कोशिश न करें, हालांकि धीमी गति से आप मानक foreach विधि का उपयोग करने से बहुत खराब कर सकते हैं।

एमएसडीएन पर आधिकारिक दस्तावेज के अनुसार, एक शब्दकोश पर फिर से शुरू करने का मानक तरीका है:

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}

मैंने एक शब्दकोश पर लूप के लिए एक विस्तार लिखा था।

public static class DictionaryExtension
{
    public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
        foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
            action(keyValue.Key, keyValue.Value);
        }
    }
}

फिर आप कॉल कर सकते हैं

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));

मैं .NET 4.0+ का लाभ उठाऊंगा और मूल रूप से स्वीकार किए गए एक को अद्यतन उत्तर प्रदान करूंगा:

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}

foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));

एक शब्दकोश को फिर से शुरू करने के लिए सरलतम रूप:

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}

मुझे एमएसडीएन पर डिक्शनरीबेस क्लास के लिए प्रलेखन में यह विधि मिली है:

foreach (DictionaryEntry de in myDictionary)
{
     //Do some stuff with de.Value or de.Key
}

यह एकमात्र ऐसा था जिसे मैं डिक्शनरीबेस से विरासत में प्राप्त कक्षा में सही तरीके से काम करने में सक्षम था।


शब्दकोश <TKey, TValue> यह सी # में एक सामान्य संग्रह वर्ग है और यह डेटा को प्रमुख मान प्रारूप में संग्रहीत करता है। के लिए अद्वितीय होना चाहिए और यह शून्य नहीं हो सकता है जबकि मान डुप्लिकेट और शून्य हो सकता है। शब्दकोश में प्रत्येक आइटम जैसा है KeyValuePair <TKey, TValue> संरचना के रूप में माना जाता है जो एक कुंजी और उसके मूल्य का प्रतिनिधित्व करता है। और इसलिए हमें तत्व के पुनरावृत्ति के दौरान तत्व प्रकार KeyValuePair <TKey, TValue> लेना चाहिए। नीचे उदाहरण है।

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");

foreach (KeyValuePair<int, string> item in dict)
{
    Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}

आम तौर पर, एक विशिष्ट संदर्भ के बिना "सबसे अच्छा तरीका" मांगना यह पूछना है कि सबसे अच्छा रंग क्या है।

एक तरफ, कई रंग हैं और कोई सर्वश्रेष्ठ रंग नहीं है। यह आवश्यकता पर निर्भर करता है और अक्सर स्वाद पर भी निर्भर करता है।

दूसरी ओर, सी # में एक शब्दकोश पर फिर से शुरू करने के कई तरीके हैं और कोई अच्छा तरीका नहीं है। यह आवश्यकता पर निर्भर करता है और अक्सर स्वाद पर भी निर्भर करता है।

सबसे सरल तरीका

foreach (var kvp in items)
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

यदि आपको केवल मूल्य की आवश्यकता है (इसे item को कॉल करने की अनुमति देता है, तो kvp.Value से अधिक पठनीय)।

foreach (var item in items.Values)
{
    doStuff(item)
}

यदि आपको एक विशिष्ट सॉर्ट ऑर्डर की आवश्यकता है

आम तौर पर, शुरुआती एक शब्दकोश की गणना के आदेश के बारे में हैरान हैं।

LINQ एक संक्षिप्त वाक्यविन्यास प्रदान करता है जो आदेश (और कई अन्य चीजें) निर्दिष्ट करने की अनुमति देता है, उदाहरण के लिए:

foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

फिर आपको केवल मूल्य की आवश्यकता हो सकती है। LINQ भी एक संक्षिप्त समाधान प्रदान करता है:

  • सीधे मूल्य पर पुनरावृत्त करें (इसे item को कॉल करने की अनुमति देता है, kvp.Value से अधिक पठनीय)
  • लेकिन चाबियाँ द्वारा क्रमबद्ध

यह रहा:

foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
    doStuff(item)
}

इन उदाहरणों से आप कई और वास्तविक दुनिया के उपयोग के मामले कर सकते हैं। यदि आपको किसी विशिष्ट क्रम की आवश्यकता नहीं है, तो बस "सबसे सरल तरीका" (ऊपर देखें) से चिपके रहें!


बस मेरा 2 प्रतिशत जोड़ना चाहता था, क्योंकि सबसे अधिक जवाब foreach-loop से संबंधित हैं। कृपया, निम्न कोड पर एक नज़र डालें:

Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();

//Add some entries to the dictionary

myProductPrices.ToList().ForEach(kvP => 
{
    kvP.Value *= 1.15;
    Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
});

Altought यह 'टॉलिस्ट ()' का एक अतिरिक्त कॉल जोड़ता है, थोड़ा सा प्रदर्शन-सुधार हो सकता है (जैसा कि यहां बताया गया है कि कुछ शब्दकोशों के साथ foreach बनाम कुछ .istach () {} ), espacially जब बड़े शब्दकोश के साथ काम करते हैं और समानांतर में चल रहे हैं विकल्प / बिल्कुल असर नहीं होगा।

साथ ही, कृपया ध्यान दें कि आप foreach-loop के अंदर 'मान' प्रॉपर्टी को मान असाइन करने में सक्षम नहीं होंगे। दूसरी तरफ, आप 'कुंजी' में भी हस्तक्षेप करने में सक्षम होंगे, संभवतः आपको रनटाइम पर परेशानी हो रही है।

जब आप केवल कुंजी और मानों को "पढ़ना" चाहते हैं, तो आप IENumerable.Select () का भी उपयोग कर सकते हैं।

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );

आपने फिर से सुझाव देने के लिए सुझाव दिया है

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary) {
    //Do some interesting things;
}

एफवाईआई, अगर मूल्य वस्तु के प्रकार हैं तो foreach काम नहीं करता है।


यदि कहें, तो आप डिफ़ॉल्ट रूप से मूल्य संग्रह पर पुन: प्रयास करना चाहते हैं, मुझे विश्वास है कि आप IENumerable <>, जहां टी शब्दकोश में मान ऑब्जेक्ट का प्रकार है, और "यह" एक शब्दकोश है।

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}

शब्दकोश विशेष सूचियां हैं, जबकि सूची में प्रत्येक मान में एक कुंजी है जो एक चर भी है। एक शब्दकोश का एक अच्छा उदाहरण एक फोन बुक है।

   Dictionary<string, long> phonebook = new Dictionary<string, long>();
    phonebook.Add("Alex", 4154346543);
    phonebook["Jessica"] = 4159484588;

ध्यान दें कि एक शब्दकोश को परिभाषित करते समय, हमें दो प्रकार के साथ एक सामान्य परिभाषा प्रदान करने की आवश्यकता होती है - कुंजी का प्रकार और मूल्य का प्रकार। इस मामले में, कुंजी एक स्ट्रिंग है जबकि मान एक पूर्णांक है।

शब्दकोश में एकल मान जोड़ने के दो तरीके भी हैं, या तो ब्रैकेट ऑपरेटर का उपयोग कर या ऐड विधि का उपयोग कर।

यह जांचने के लिए कि क्या एक शब्दकोश में एक निश्चित कुंजी है, हम ContainsKey विधि का उपयोग कर सकते हैं:

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

if (phonebook.ContainsKey("Alex"))
{
    Console.WriteLine("Alex's number is " + phonebook["Alex"]);
}

किसी शब्दकोश से किसी आइटम को निकालने के लिए, हम निकालें विधि का उपयोग कर सकते हैं। किसी कुंजी से अपनी कुंजी से किसी आइटम को निकालना तेज़ और बहुत ही कुशल है। किसी आइटम से अपने मूल्य का उपयोग करके किसी आइटम को हटाते समय, प्रक्रिया धीमी और अक्षम होती है, शब्दकोश निकालें फ़ंक्शन निकालें के विपरीत।

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

phonebook.Remove("Jessica");
Console.WriteLine(phonebook.Count);

आपके मामले में, आप क्या कर सकते हैं:

z = dict(x, **y)

यह वही होगा, जैसा कि आप चाहते हैं, अंतिम नियम को z , और कुंजी b के मान को दूसरे ( y ) dict के मान से ठीक से ओवरराइड किया जाए:

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

यदि आप पायथन 3 का उपयोग करते हैं, तो यह केवल थोड़ा और जटिल है। z बनाने के लिए:

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)






c# dictionary loops