c# معنى ما أفضل طريقة للتكرار عبر القاموس؟




معنى كلمة عنوان بالانجليزي (17)

أبسط شكل لتكرار القاموس:

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

https://code.i-harness.com

لقد رأيت عدة طرق مختلفة للتكرار عبر قاموس في C #. هل هناك طريقة قياسية؟


أردت فقط إضافة سنتي 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));
});

يضيف هذا دعوة إضافية ".ToList ()" ، قد يكون هناك تحسن طفيف في الأداء (كما هو موضح هنا foreach مقابل بعض List.Foreach () {} ) ، espacially عند العمل مع قواميس كبيرة وتشغيل في موازاة لا الخيار / لن يكون لها تأثير على الإطلاق.

كذلك ، يرجى ملاحظة أنك لن تتمكن من تعيين قيم لقيمة "القيمة" داخل حلقة foreach. من ناحية أخرى ، سوف تكون قادرًا على التعامل مع "المفتاح" أيضًا ، مما قد يجعلك تواجه مشكلة في وقت التشغيل.

عندما تريد فقط "قراءة" مفاتيح وقيم ، قد تستخدم أيضًا IEnumerable.Select ().

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

أود أن أقول أن foreach هي الطريقة القياسية ، على الرغم من أنه يعتمد بشكل واضح على ما تبحث عنه

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

هل هذا ما تبحث عنه؟


إذا قلنا ، أنك تريد التكرار أكثر من مجموعة القيم بشكل افتراضي ، أعتقد أنه يمكنك تنفيذ IEnumerable <> ، حيث T هو نوع كائن القيم في القاموس ، و "هذا" هو قاموس.

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

اعتبارا من C # 7 ، يمكنك تفكيك الكائنات في المتغيرات. أعتقد أن هذا هو أفضل طريقة للتكرار عبر القاموس.

مثال:

إنشاء طريقة ملحق على KeyValuePair<TKey, TVal> التي KeyValuePair<TKey, TVal> :

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey, out TVal val)
{
   key = pair.Key;
   val = 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}");
}

الطريقة القياسية للتكرار عبر قاموس ، وفقًا للوثائق الرسمية على MSDN هي:

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

باستخدام .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;
    }
}

باستخدام 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> الخاص بك IDictionary<TKey, TValue> إلى مجموعة IDictionary<TKey, TValue> مكتوبة بقوة ، مما يسمح لك باستخدام هذا التركيب الجديد المريح.

إنه يحول - فقط- إدخالات القاموس المطلوبة إلى tuples ، لذلك لا يحول القاموس بأكمله إلى مجموعات ، لذلك لا توجد مخاوف متعلقة بالأداء مرتبطة بذلك.

هناك تكلفة ثانوية بسيطة تسمى طريقة التمديد لإنشاء فئة مقارنة مع استخدام KeyValuePair مباشرة ، والتي لا ينبغي أن تكون مشكلة إذا كنت تقوم بتعيين خصائص KeyValuePair 's Key and Value للمتغيرات حلقة جديدة على أي حال.

من الناحية العملية ، فإن هذه البنية الجديدة تناسب بشكل جيد للغاية في معظم الحالات ، باستثناء سيناريوهات الأداء المنخفض للغاية ذات المستوى المنخفض ، حيث لا يزال أمامك خيار عدم استخدامه ببساطة على تلك النقطة المحددة.

تحقق من ذلك: مدونة MSDN - ميزات جديدة في C # 7


بشكل عام ، إن السؤال عن "أفضل طريقة" بدون سياق محدد هو مثل سؤال ما هو أفضل لون.

من ناحية ، هناك العديد من الألوان وليس هناك لون أفضل. يعتمد ذلك على الحاجة وعلى المذاق أيضًا.

من ناحية أخرى ، هناك العديد من الطرق للتكرار عبر قاموس في C # وليس هناك طريقة أفضل. يعتمد ذلك على الحاجة وعلى المذاق أيضًا.

الطريق الأكثر مباشرة

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

إذا كنت بحاجة إلى القيمة فقط (يسمح لك بالاتصال به ، أكثر قابلية للقراءة من 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)
}

هناك العديد من حالات الاستخدام في العالم الحقيقي التي يمكنك القيام بها من هذه الأمثلة. إذا لم تكن بحاجة إلى طلب معين ، فعليك التمسك بـ "الطريقة الأكثر مباشرة" (انظر أعلاه)!


سوف أستفيد من ميزة .NET 4.0+ وأقدم إجابة محدثة للواجهة المقبولة في الأصل:

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

في بعض الحالات ، قد تحتاج إلى عداد يمكن توفيره من خلال تنفيذ الحل المتكرر. لهذا ، يوفر LINQ ElementAt مما يتيح ما يلي:

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

لقد اقترحت أدناه للتكرار

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

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

لمعلوماتك ، لا تعمل foreach إذا كانت القيمة من كائن الكتابة.


لقد وجدت هذه الطريقة في الوثائق لفئة DictionaryBase على MSDN:

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

كان هذا هو الوحيد الذي تمكنت من الحصول على وظائف بشكل صحيح في فئة ورثت من DictionaryBase.


هناك الكثير من الخيارات. بلدي المفضل الشخصي هو عن طريق KeyValuePair

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

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

يمكنك أيضًا استخدام مجموعات المفاتيح والقيم


يمكنك أيضًا تجربة ذلك في القواميس الكبيرة للمعالجة متعددة مؤشرات الترابط.

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

القاموس <TKey، TValue> هو عبارة عن فئة مجموعة عامة في c # ويقوم بتخزين البيانات بتنسيق قيمة المفتاح. يجب أن يكون المفتاح فريدًا وأنه لا يمكن أن يكون خاليًا بينما القيمة يمكن أن تكون مكررة و null.As كل عنصر في القاموس هو تعامل على أنها 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);
}

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

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




loops