एक शब्दकोश पर पुनरावृति करने का सबसे अच्छा तरीका क्या है?


2625

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


108
मुझे आश्चर्य है कि इस सवाल के कई उत्तर हैं, साथ में एक 923 बार उत्कीर्ण किया गया है (फ़ॉर्वर्ड ऑफ़कोर्स का उपयोग करता है) .. मैं बहस करूँगा, या कम से कम यह जोड़ दूंगा कि यदि आपको किसी शब्दकोष पर चलना है, तो संभावना है कि आप हैं गलत तरीके से / अनुचित तरीके से उपयोग करते हुए .. मुझे यह टिप्पणी करनी पड़ी, क्योंकि मैंने शब्दकोशों को उन तरीकों से दुरुपयोग करते देखा है जो IMHO के लिए उपयुक्त नहीं थे ... हाँ, दुर्लभ परिस्थितियाँ हो सकती हैं जब आप शब्दकोश को देखने के बजाय, इसे दोहराते हैं, जो कि है इसके लिए डिज़ाइन किया गया है .. कृपया इसे ध्यान में रखें, इससे पहले कि कोई शब्दकोश में पुनरावृति करने से पहले सोचें।
विकास गुप्ता

74
@VikasGupta कुंजी-मूल्य जोड़े के संग्रह के साथ कुछ करने के लिए आप क्या सुझाव देंगे जब आपको पता नहीं होगा कि चाबियाँ क्या होने जा रही हैं?
नास

26
@displayName यदि आप प्रत्येक कुंजी-मूल्य जोड़ी के साथ कुछ करना चाहते हैं, लेकिन मूल्यों को देखने के लिए उपयोग करने के लिए कुंजियों का संदर्भ नहीं है, तो आप शब्दकोश पर अधिकार करेंगे, ठीक है? मैं सिर्फ इशारा कर रहा था कि ऐसा कई बार हो सकता है जो आप करना चाहते हैं, विकास के दावे के बावजूद कि यह आमतौर पर गलत उपयोग है।
nasch

34
यह कहना कि यह गलत उपयोग है इसका मतलब है कि एक बेहतर विकल्प है। वह विकल्प क्या है?
काइल डेलाने

40
विकासगुप्त गलत है, मैं इस बात की पुष्टि कर सकता हूं कि गैर-सैद्धांतिक परिदृश्यों में उच्च प्रदर्शन C # और C ++ प्रोग्रामिंग के कई वर्षों के बाद। वास्तव में अक्सर ऐसे मामले होते हैं जहां कोई एक शब्दकोश बनाता है, अद्वितीय कुंजी-मूल्य जोड़े को संग्रहीत करता है, और फिर इन मूल्यों पर पुनरावृति करता है, जो संग्रह के भीतर अद्वितीय कुंजी साबित होते हैं। कोई और संग्रह बनाना शब्दकोश चलना से बचने के लिए वास्तव में अक्षम और महंगा तरीका है। कृपया अपनी बात स्पष्ट करने वाले प्रश्न के उत्तर के रूप में एक अच्छा विकल्प प्रदान करें, अन्यथा आपकी टिप्पणी बहुत निरर्थक है।
s --unıɐ ןɐ qɐp

जवाबों:


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

29
क्या होगा अगर मुझे शब्दकोश में कुंजी / मान के प्रकार का ठीक-ठीक पता नहीं है। उपयोग करना var entryउस मामले में बेहतर है, और इस प्रकार मैंने इस उत्तर को उपरोक्त के बजाय एक दूसरे लुक पर वोट दिया
ओजैर काफरे

93
@OzairKafray का उपयोग करके varजब आप नहीं जानते कि प्रकार आम तौर पर बुरा अभ्यास है।
नाटे

52
यह उत्तर बेहतर है क्योंकि पाब्लो आलसी कोडर "var" उपयोग के लिए डिफ़ॉल्ट नहीं था जो रिटर्न प्रकार को बाधित करता है।
मंकीवॉच

119
@MonkeyWrench: मेह। विज़ुअल स्टूडियो जानता है कि प्रकार क्या है; आपको बस इतना पता करना है कि पता लगाने के लिए चर पर होवर करें।
रॉबर्ट हार्वे

31
जैसा कि मैं इसे समझता हूं, varकेवल तभी काम करता है जब प्रकार संकलित समय पर जाना जाता है। यदि Visual Studio प्रकार जानता है तो यह आपके लिए भी उपलब्ध है।
काइल डेलानी

866

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

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कीवर्ड एक वैकल्पिक C # 3.0 और ऊपर की सुविधा है, आप अपनी कुंजी / मानों के सटीक प्रकार का भी उपयोग कर सकते हैं)


11
var सुविधा आपके पहले कोड ब्लॉक के लिए सबसे अधिक आवश्यक है :)
nawfal

27
मैं सराहना करता हूं कि यह उत्तर बताता है कि आप चाबियों या मूल्यों को स्पष्ट रूप से बता सकते हैं।
Rotsiser Mho

11
मुझे यहाँ var का उपयोग पसंद नहीं है। यह देखते हुए कि यह सिंटैक्टिक शुगर है, इसका उपयोग यहां क्यों करें? जब कोई कोड को पढ़ने की कोशिश कर रहा होता है, तो उन्हें myDictionary( प्रकार का वास्तविक नाम जब तक) प्रकार निर्धारित करने के लिए कोड के चारों ओर कूदना होगा । मुझे लगता है कि var का उपयोग करना अच्छा है, जब प्रकार स्पष्ट है जैसे, var x = "some string"लेकिन जब यह तुरंत स्पष्ट नहीं होता है, तो मुझे लगता है कि यह आलसी कोडिंग है जो कोड रीडर / समीक्षक को चोट पहुंचाता है
जेम्स विर्ज़बा

8
varमेरी राय में, संयम से इस्तेमाल किया जाना चाहिए। विशेष रूप से यहां, यह रचनात्मक नहीं है: प्रकार KeyValuePairप्रश्न की संभावना है।
सिनजई

3
varएक अनूठा उद्देश्य है और मुझे विश्वास नहीं है कि यह 'सिंटैक्टिक' चीनी है। उद्देश्यपूर्ण तरीके से इसका उपयोग करना एक उपयुक्त दृष्टिकोण है।
जोशुआ के

159

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

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

21
'.ElementAt' पद्धति का उपयोग करने के लिए, याद रखें: System.Linq का उपयोग करना; यह एफएक्स में झुकाव नहीं है। ऑटो उत्पन्न परीक्षण कक्षाएं।
टीनिया

14
यदि आप कुंजियों से जुड़े मानों को संशोधित कर रहे हैं तो यह जाने का तरीका है। अन्यथा एक अपवाद को फेंक दिया जाता है जब संशोधित और फ़ॉरच () का उपयोग किया जाता है।
माइक डी क्लार्क

27
नहीं है ElementAtएक हे (एन) आपरेशन?
आर्टुरो टॉरेस सैंचेज़

162
यह उत्तर इतने सारे अपवाह का पूरी तरह से अवांछनीय है। एक शब्दकोश में कोई निहित आदेश नहीं है, इसलिए .ElementAtइस संदर्भ में उपयोग करने से सूक्ष्म कीड़े हो सकते हैं। अधिक गंभीर है Arturo के ऊपर बिंदु। आप dictionary.Count + 1एक ऑपरेशन के लिए O (n ^ 2) जटिलता के लिए अग्रणी शब्दकोश की पुनरावृत्ति करेंगे जो केवल O (n) होना चाहिए। यदि आपको वास्तव में एक सूचकांक की आवश्यकता है (यदि आप करते हैं, तो आप शायद पहले स्थान पर गलत संग्रह प्रकार का उपयोग कर रहे हैं), आपको dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})इसके बजाय पुनरावृति करना चाहिए और .ElementAtलूप के अंदर उपयोग नहीं करना चाहिए ।
खर्च करें

5
एलिमेंटएट - ओ (एन) ऑपरेशन! गंभीरता से? यह उदाहरण है कि आपको यह कैसे नहीं करना चाहिए। ये कई upvotes?
मुकेश प्रवेशु

96

निर्भर करता है कि आप कुंजियों या मूल्यों के बाद हैं ...

MSDN Dictionary(TKey, TValue)वर्ग विवरण से:

// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
    Console.WriteLine("Key = {0}, Value = {1}", 
        kvp.Key, kvp.Value);
}

// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
    openWith.Values;

// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
    Console.WriteLine("Value = {0}", s);
}

// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
    openWith.Keys;

// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
    Console.WriteLine("Key = {0}", s);
}

82

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

एक हाथ, कई रंग हैं और कोई सबसे अच्छा रंग नहीं है। यह जरूरत पर निर्भर करता है और अक्सर स्वाद पर भी।

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

सबसे सीधा रास्ता

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 भी एक संक्षिप्त समाधान प्रदान करता है:

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

यह रहा:

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

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


अंतिम एक होना चाहिए .Valuesऔर एक चयनित खंड नहीं होना चाहिए ।
माफि

@Mafii क्या आप सुनिश्चित हैं? ऑर्डरबाय द्वारा लौटाए गए मान KeyValuePair प्रकार के नहीं हैं, उनका कोई Valueक्षेत्र नहीं है । सटीक प्रकार मैं यहाँ देख रहा हूँ IOrderedEnumerable<KeyValuePair<TKey, TValue>>। शायद आपका मतलब कुछ और था? क्या आप एक पूरी लाइन लिख सकते हैं, जिसका अर्थ है कि आप क्या मतलब है (और इसका परीक्षण करें)?
स्टीफन गौरीचोन 14

मुझे लगता है कि इस उत्तर में मेरा क्या मतलब है: stackoverflow.com/a/141105/5962841 लेकिन मुझे सही करें अगर मैं कुछ उलझन में हूं
Mafii

1
@Mafii मेरे पूरे उत्तर को दोबारा पढ़ें, कोड सेक्शन के बीच स्पष्टीकरण संदर्भ को बताता है। आपके द्वारा उल्लेखित उत्तर मेरे उत्तर में दूसरे कोड खंड की तरह है (कोई आदेश आवश्यक नहीं)। वहाँ मैंने items.Valueजैसा सुझाव दिया वैसा ही लिखा । चौथे खंड के मामले में, जो आपने टिप्पणी की थी, कुंजी-मूल्य जोड़े के बजाय शब्दकोश में मूल्यों पर सीधे गणना Select()करने का कारण foreachहै। यदि किसी तरह आप Select()इस मामले में पसंद नहीं करते हैं, तो आप तीसरे कोड अनुभाग को पसंद कर सकते हैं। चौथे खंड का बिंदु यह दिखाना है कि कोई LINQ के साथ संग्रह को पूर्व-संसाधित कर सकता है।
स्टीफन गौरिचोन

1
यदि आप करते हैं तो .Keys.Orderby()आप कुंजियों की सूची पर पुनरावृति करेंगे। अगर आप की जरूरत है, ठीक है। यदि आपको मूल्यों की आवश्यकता है, तो लूप में आपको मूल्य प्राप्त करने के लिए प्रत्येक कुंजी पर शब्दकोश को क्वेरी करना होगा। कई परिदृश्यों में यह व्यावहारिक अंतर नहीं बनाएगा। उच्च-प्रदर्शन परिदृश्य में, यह होगा। जैसे मैंने उत्तर की शुरुआत में लिखा था: "कई तरीके (...) हैं और कोई सबसे अच्छा तरीका नहीं है। यह जरूरत पर निर्भर करता है और अक्सर स्वाद पर भी निर्भर करता है।"
स्टीफन गौरिचोन

53

मैं कहूंगा कि फॉर्च्यूनर मानक तरीका है, हालांकि यह स्पष्ट रूप से इस बात पर निर्भर करता है कि आप क्या खोज रहे हैं

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

कि तुम क्या देख रहे हो?


42
उम, भ्रमित करने के बजाय आइटम "मान" नाम नहीं दे रहा है? आप आमतौर पर "value.Key" और "value.Value" जैसे सिंटैक्स का उपयोग कर रहे होंगे, जो किसी और के लिए बहुत सहज नहीं है जो कोड को पढ़ रहे होंगे, खासकर यदि वे इस बात से परिचित नहीं हैं कि .Net शब्दकोश कैसे लागू किया जाता है। ।
रेनीपेट

3
@RenniePet kvpसामान्यतः KeyValuePair उदाहरणों नाम के लिए प्रयोग किया जाता है जब बार-बार दोहराना शब्दकोशों और संबंधित डेटा संरचनाओं पर: foreach(var kvp in myDictionary){...
mbx

37

आप मल्टीथ्रेडेड प्रोसेसिंग के लिए बड़े शब्दकोशों पर भी इसे आज़मा सकते हैं।

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});

8
@IiMaxx और अधिक महत्वपूर्ण अगर ये आइटम एक-दूसरे पर निर्भर नहीं होते हैं
Mafii

36

C # 7.0 ने डिकंस्ट्रक्टर्स को पेश किया और यदि आप .NET कोर 2.0+ एप्लिकेशनका उपयोग कर रहे हैं, तो संरचनाआपके लिएKeyValuePair<>पहले से ही शामिल हैDeconstruct()। तो आप कर सकते हैं:

var dic = new Dictionary<int, string>() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
foreach (var (key, value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}
//Or
foreach (var (_, value) in dic) {
    Console.WriteLine($"Item [NO_ID] = {value}");
}
//Or
foreach ((int key, string value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}

यहां छवि विवरण दर्ज करें


5
यदि आपका .NET .NET का उपयोग करते हुए, जो कि 4.7.2 तक कम से कम KeyValuePair पर Deconstruct नहीं है, तो इसे आज़माएं:foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
nwsmith

29

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

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

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

शब्दकोशों को लुकअप के लिए ऑप्टिमाइज़ किया गया है, इसलिए इस बात को ध्यान में रखते हुए कि मैंने दो तरीके बनाए हैं। एक बस एक फॉर्च्यूनर करता है, दूसरा फिर कुंजियों को दिखाता है।

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";
}

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

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

यहाँ RunTest तरीका है जो आपको यह कल्पना करने में मदद करता है कि क्या चल रहा है।

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);
}

यहाँ सामान्य फ़ॉरेस्ट रन 0.2820564 सेकंड (लगभग दस गुना अधिक एक एकल पुनरावृत्ति से लिया - जैसा कि आप उम्मीद करेंगे) लिया। कुंजियों पर पुनरावृत्ति ने 2.2249449 सेकंड का समय लिया।

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

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

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

11
आपको डेटटाइम के बजाय स्टॉपवॉच जैसी किसी चीज़ से मापना चाहिए: hanselman.com/blog/…
यहां तक ​​कि

2
क्या आप अपने परीक्षण परिदृश्य का वर्णन कर सकते हैं, आपके शब्दकोश में कितने आइटम हैं, आपने औसत समय की गणना करने के लिए कितनी बार अपना परिदृश्य चलाया, ...
WiiMaxx

3
दिलचस्प बात यह है कि डिक्शनरी में आपके पास जो डेटा है, उसके आधार पर आपको अलग-अलग परिणाम मिलेंगे। डिक्शनरी पर इटामेटेरेट करने के दौरान एन्यूमरेटर फ़ंक्शन को बहुत सारे खाली स्लॉट्स को डिक्शनरी में छोड़ना पड़ता है। यदि शब्दकोश भरा हुआ है तो आधे खाली होने की तुलना में छोड़ने के लिए कम खाली स्लॉट होंगे।
मार्टिन ब्राउन

26

बहुत सारे विकल्प हैं। मेरा व्यक्तिगत पसंदीदा KeyValuePair द्वारा है

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

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

आप कुंजी और मान संग्रह का उपयोग भी कर सकते हैं


14

साथ .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;
    }
}

9
यह गलत है। .NET 4.7 बस में ValueTupleबनाया गया है। यह पुराने संस्करणों के लिए एक नगेट पैकेज के रूप में उपलब्ध है। इससे भी महत्वपूर्ण बात, Deconstructविधि के लिए C # 7.0+ की आवश्यकता है, जिसके लिए एक डिकंस्ट्रक्टर के रूप में काम करना है var (fruit, number) in fruits
डेविड अरनो

13

C # 7 के अनुसार, आप ऑब्जेक्ट्स को वेरिएबल्स में डिक्रिप्ट कर सकते हैं। मेरा मानना ​​है कि यह एक शब्दकोश पर पुनरावृति करने का सबसे अच्छा तरीका है।

उदाहरण:

KeyValuePair<TKey, TVal>उस पर डिकॉन्स्ट्रक्ट करता है एक विस्तार विधि बनाएँ :

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey key, out TVal value)
{
   key = pair.Key;
   value = pair.Value;
}

Dictionary<TKey, TVal>निम्नलिखित तरीके से किसी पर भी फेरबदल करें

// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();

// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
   Console.WriteLine($"{key} : {value}");
}

10

आपने इसे पुनरावृति का सुझाव दिया है

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

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

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


4
कृपया विस्तृत करें: foreachकाम नहीं करेगा यदि मूल्य किस प्रकार का है object? अन्यथा यह बहुत मतलब नहीं है।
मार्क एल।

9

एक शब्दकोश को पुनरावृत्त करने के लिए सबसे सरल रूप:

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

9

C # 7 का उपयोग करते हुए , अपने समाधान की किसी भी परियोजना में इस विस्तार विधि को जोड़ें :

public static class IDictionaryExtensions
{
    public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
        this IDictionary<TKey, TValue> dict)
    {
        foreach (KeyValuePair<TKey, TValue> kvp in dict)
            yield return (kvp.Key, kvp.Value);
    }
}


और इस सरल वाक्यविन्यास का उपयोग करें

foreach (var(id, value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


या यह एक, यदि आप पसंद करते हैं

foreach ((string id, object value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


पारंपरिक के स्थान पर

foreach (KeyValuePair<string, object> kvp in dict)
{
    string id = kvp.Key;
    object value = kvp.Value;

    // your code using 'id' and 'value'
}


विस्तार विधि KeyValuePairआपके IDictionary<TKey, TValue>एक मजबूत टाइप में तब्दील हो जाती है tuple, जिससे आप इस नए आरामदायक वाक्यविन्यास का उपयोग कर सकते हैं।

यह धर्मान्तरित-अन्याय करता है - आवश्यक शब्दकोश प्रविष्टियों को tuples, इसलिए यह पूरे शब्दकोश को धर्मान्तरित नहीं करता है, इसलिए इससे tuplesसंबंधित प्रदर्शन चिंताएं नहीं हैं।

सीधे tupleउपयोग करने की तुलना में ए बनाने के लिए एक्सटेंशन मेथड को कॉल करने के लिए केवल एक मामूली लागत है KeyValuePair, जो एक मुद्दा नहीं होना चाहिए यदि आप किसी भी तरह के नए KeyValuePairगुणों Keyऔर Valueनए लूप चर को असाइन कर रहे हैं ।

व्यवहार में, यह नया वाक्य-विन्यास अधिकांश मामलों के लिए बहुत उपयुक्त है, निम्न-स्तरीय अल्ट्रा-उच्च प्रदर्शन परिदृश्यों को छोड़कर, जहां आपके पास अभी भी उस विशिष्ट स्थान पर इसका उपयोग नहीं करने का विकल्प है।

इसे देखें: MSDN ब्लॉग - C # 7 में नई सुविधाएँ


1
कुंजी-मूल्य-जोड़ी के लिए 'आरामदायक' ट्यूपल्स को प्राथमिकता देने का क्या कारण होगा? मैं यहाँ एक लाभ नहीं देख रहा हूँ। आपके टपल में एक कुंजी और एक मूल्य होता है, इसलिए कुंजी-मूल्य-युग्म होता है।
मार्टन

4
हाय मैर्टन, आपके प्रश्न के लिए धन्यवाद। मुख्य लाभ अतिरिक्त प्रोग्रामिंग प्रयास के बिना कोड पठनीयता है। KeyValuePair के साथ एक को हमेशा फॉर्म का उपयोग करना चाहिए kvp.Keyऔर kvp.Valueक्रमशः कुंजी और मूल्य का उपयोग करना चाहिए । ट्यूपल्स के साथ आपको फ़ॉरच ब्लॉक के अंदर और परिवर्तनशील घोषणाओं का उपयोग किए बिना, कुंजी और मान को नाम देने की सुविधा मिलती है। उदाहरण के लिए, आप अपनी कुंजी को नाम दे सकते हैं factoryNameऔर मान models, जो कि विशेष रूप से उपयोगी है जब आपको नेस्टेड लूप (शब्दकोशों के शब्दकोश) मिलते हैं: कोड रखरखाव बहुत आसान हो जाता है। इसे मात्र आजमाएं! ;-)
s Sepunıɔ ɐ q --p

7

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

    public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
    {
        foreach (KeyValuePair<T, U> p in d) { a(p); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
    {
        foreach (T t in k) { a(t); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
    {
        foreach (U u in v) { a(u); }
    }

इस तरह मैं इस तरह कोड लिख सकता हूं:

myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););

6

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

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


+1 प्रदर्शन में लाने के लिए। वास्तव में, शब्दकोष पर ही ध्यान देने से कुछ ओवरहेड शामिल होते हैं यदि आपको सभी की आवश्यकता है मान। यह ज्यादातर KeyValuePair स्ट्रक्चर्स में मान या संदर्भ कॉपी करने के कारण है।
जानूस व्रूस

1
FYI करें कि लिंक में अंतिम परीक्षण गलत चीज का परीक्षण है: यह मानों की अवहेलना करने वाले मानों पर पुनरावृत्ति को मापता है, जबकि पिछले दो परीक्षण मूल्य का उपयोग करते हैं।
वर्धमान ताजा

5

मैंने MSDN पर DictionaryBase वर्ग के लिए प्रलेखन में यह तरीका पाया:

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

यह एकमात्र ऐसा वर्ग था, जो डिक्शनबेस से विरासत में मिली कक्षा में सही ढंग से काम करने में सक्षम था।


3
यह तब दिखता है जब शब्दकोश के गैर-जेनेरिक संस्करण का उपयोग करते समय ... यानी .NET फ्रेमवर्क 2.0 से पहले।
joedotnot

@ joed0tnot: यह Hashtableवस्तुओं के लिए उपयोग किया जाने वाला गैर-जेनेरिक संस्करण है
sɔunıɔ ןɐ q'p

5

foreachसबसे तेज़ है और यदि आप केवल ___.Valuesइसे खत्म करते हैं , तो यह तेज़ भी है

यहां छवि विवरण दर्ज करें


आप संस्करण ContainsKey()में क्यों बुला रहे हैं for? अतिरिक्त ओवरहेड जोड़ता है जो आपके द्वारा तुलना किए जा रहे कोड में मौजूद नहीं है। TryGetValue()उस सटीक को बदलने के लिए मौजूद है "यदि कुंजी मौजूद है, तो कुंजी को" पैटर्न के साथ प्राप्त करें। इसके अलावा, अगर dictसे पूर्णांकों का एक सन्निहित रेंज शामिल 0करने के लिए dictCount - 1, तुम्हें पता है इंडेक्सर असफल नहीं हो सकता; अन्यथा, dict.Keysआपको जो पुनरावृत्त होना चाहिए। किसी भी तरह से, कोई ContainsKey()/ TryGetValue()जरूरत है। अंतिम, कृपया कोड के स्क्रीनशॉट पोस्ट न करें।
BACON

3

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

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

3

MSDN पर आधिकारिक प्रलेखन के अनुसार, एक शब्दकोश पर पुनरावृति करने का मानक तरीका है:

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

2

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

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));

आपने एक ForEachविधि को परिभाषित किया है जिसमें आपके पास foreach (...) { }... अनावश्यक जैसा लगता है।
मार्टन

1

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

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

1

बस मेरा 2 प्रतिशत जोड़ना चाहते थे, क्योंकि अधिकांश उत्तर फॉरच-लूप से संबंधित थे। कृपया, निम्नलिखित कोड पर एक नज़र डालें:

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));
});

यह सोचा गया कि '.TLList ()' का एक अतिरिक्त कॉल आता है, इसमें थोड़ा सा प्रदर्शन-सुधार हो सकता है (जैसा कि यहां बताया गया है। someList.Foreach () {} ), बड़े शब्दों के साथ काम करते समय और समानांतर रूप से चलने पर स्पष्ट रूप से नहीं है विकल्प / का असर बिल्कुल नहीं होगा।

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

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

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

5
बिना किसी कारण के पूरे संग्रह की नकल करने से प्रदर्शन में सुधार नहीं होगा। यह नाटकीय रूप से कोड को धीमा कर देगा, साथ ही कोड की मेमोरी फ़ुटप्रिंट को दोगुना कर देगा जो कि लगभग कोई अतिरिक्त मेमोरी का उपभोग नहीं करना चाहिए।
सेवी

मैं साइड-इफ़ेक्ट 'List.ForEach' विधि से बचता हूँ: foreachसाइड-इफ़ेक्ट विजिबिलिटी को बढ़ाता है , जहाँ यह होता है।
user2864740

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

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

2
इस उत्तर में अधिक औचित्य / विवरण होने की आवश्यकता है। क्या AggregateObjectजोड़ता है KeyValuePair? प्रश्न में अनुरोध के अनुसार "पुनरावृत्ति" कहां है?
मार्क एल।

शब्दकोश पर पुनरावृत्तियों का चयन करें और हमें प्रत्येक ऑब्जेक्ट पर काम करने की अनुमति देता है। यह उतना सामान्य नहीं है foreach, लेकिन मैंने इसका भरपूर उपयोग किया है। क्या मेरा जवाब सही मायने में नीच है?
Pixar

नहीं, परिणाम को प्रभावित करने के Select लिए पुनरावृत्ति का उपयोग करता है , लेकिन स्वयं एक पुनरावृत्ति नहीं है। चीजों के प्रकार जो कि पुनरावृत्ति ( foreach) के लिए उपयोग किए जाते हैं - विशेष रूप से साइड-इफेक्ट्स के साथ ऑपरेशन - लाइनक के दायरे से बाहर हैं, जिसमें शामिल हैं Select। लैम्बडा तब तक नहीं चलेगा जब तक aggregateObjectCollectionकि वास्तव में गणना नहीं हो जाती। यदि इस उत्तर को "पहले पथ" के रूप में लिया जाता है (यानी, सीधे से पहले इस्तेमाल किया जाता है foreach) यह बुरी प्रथाओं को प्रोत्साहित करता है। स्थिति के अनुसार, Linq ऑपरेशंस हो सकते हैं जो किसी शब्दकोश को पुनरावृत्त करने से पहले मददगार होते हैं , लेकिन यह पूछे गए सवाल को संबोधित नहीं करता है।
मार्क एल।

0

शब्दकोश <TKey, TValue> यह c # में एक सामान्य संग्रह वर्ग है और यह डेटा को मुख्य मूल्य प्रारूप में संग्रहीत करता है। इसे अद्वितीय होना चाहिए और यह शून्य नहीं हो सकता है, जबकि मूल्य डुप्लिकेट और शून्य हो सकता है। शब्दकोश में प्रत्येक आइटम। 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);
}

0

यदि आप लूप के लिए उपयोग करना चाहते हैं, तो आप यह कर सकते हैं:

var keyList=new List<string>(dictionary.Keys);
for (int i = 0; i < keyList.Count; i++)
{
   var key= keyList[i];
   var value = dictionary[key];
 }

हालांकि, इसका क्या लाभ है? यह एक foreachलूप और खराब प्रदर्शन की तुलना में अधिक लंबा कोड है क्योंकि इससे पहले कि आप स्वयं इसे पुनरावृत्त करने का मौका new List<string>(dictionary.Keys)होगा, dictionary.Countइससे पहले भी इसे पुन: व्यवस्थित करेंगे। यह कहते हुए कि "सबसे अच्छा तरीका" के लिए पूछना व्यक्तिपरक है, मैं यह नहीं देखता कि यह "सबसे अच्छा तरीका" या "मानक तरीके" के रूप में कैसे योग्य होगा जो प्रश्न पूछते हैं। "यदि आप लूप के लिए उपयोग करना चाहते हैं ..." मैं " लूप का उपयोग करें " के साथ काउंटर करूंगा for
BACON

यदि आपके पास बड़ा संग्रह है और संचालन foreach में धीमा है और यदि आप संग्रह करते समय अपने संग्रह को बदल सकते हैं, तो यह आपको "संग्रह बदल गया" त्रुटि से बचाता है और इस समाधान में बेहतर प्रदर्शन है तो ElementAt का उपयोग करना।
सेक्विन दुर्गाय

मैं मानता हूं कि "संग्रह संशोधित किया गया था" अपवादों को टालना ऐसा करने का एक कारण है, हालांकि उस विशेष मामले को प्रश्न में नहीं बताया गया था और एक हमेशा कर सकता था foreach (var pair in dictionary.ToArray()) { }। फिर भी, मुझे लगता है कि विशिष्ट परिदृश्य (नों) के उत्तर में स्पष्ट करना अच्छा होगा, जिसमें कोई इस कोड और ऐसा करने के निहितार्थ का उपयोग करना चाहेगा।
बैकोन

हाँ आप सही हैं लेकिन एलीमेंट के साथ यहाँ एक उत्तर दिया गया है और इसकी बहुत उच्च प्रतिष्ठा है और मैंने इस उत्तर में प्रवेश किया :)
सीकिन दुर्गाय

-1

linq के साथ सरल

 Dictionary<int, string> dict = new Dictionary<int, string>();
 dict.Add(1, "American Ipa");
 dict.Add(2, "Weiss");
 dict.ToList().ForEach(x => Console.WriteLine($"key: {x.Key} | value: {x.Value}") );

मैं देख रहा हूं कि आप फोन कर रहे हैं ToList()क्योंकि ForEach()केवल List<>कक्षा पर परिभाषित किया गया है , लेकिन सिर्फ इसके बजाय सभी क्यों करते हैं foreach (var pair in dict) { }? मैं कहता हूं कि यह और भी सरल है और इसमें समान मेमोरी / प्रदर्शन निहितार्थ नहीं हैं। यह सटीक समाधान पहले से ही इस उत्तर में 3.5 साल पहले से प्रस्तावित था, वैसे भी।
BACON

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

-3

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

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
}

सबसे पूर्ण निम्नलिखित है क्योंकि आप आरंभिक से शब्दकोश प्रकार देख सकते हैं, kvp 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
}

5
एक दूसरा शब्दकोश बनाना और कॉपी करना कोड पठनीयता का एक वैध समाधान नहीं है। वास्तव में, मैं यह तर्क दूंगा कि कोड को समझना कठिन होगा क्योंकि अब आपको खुद से पूछना होगा: "आखिरी आदमी ने दूसरा शब्दकोष क्यों बनाया?" यदि आप अधिक वाचाल होना चाहते हैं, तो बस विकल्प एक का उपयोग करें।
मैथ्यू गुलार्ट

मेरा बस आपको यह दिखाने का मतलब है कि जब प्रत्येक के लिए
तानाशाही
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.