java - يتكرر من خلال HashMap




loops iteration (7)

ممكن تكرار:
كيف يتم التكرار بكفاءة أعلى لكل إدخال في "خريطة"؟

ما هي أفضل طريقة للتكرار أكثر من العناصر الموجودة في HashMap ؟


Answers

يتكرر من خلال entrySet() مثل:

public static void printMap(Map mp) {
    Iterator it = mp.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry pair = (Map.Entry)it.next();
        System.out.println(pair.getKey() + " = " + pair.getValue());
        it.remove(); // avoids a ConcurrentModificationException
    }
}

قراءة المزيد عن Map .


مستخلص من المرجع كيفية التكرار عبر خريطة في جاوا :

هناك عدة طرق للتكرار فوق Map في Java. دعونا نذهب لأكثر الأساليب شيوعا ومراجعة مزاياها وعيوبها. بما أن جميع الخرائط في Java تقوم بتطبيق واجهة الخريطة ، فإن التقنيات التالية ستعمل لأي تطبيق خريطة ( HashMap ، TreeMap ، LinkedHashMap ، Hashtable ، إلخ.)

الأسلوب # 1 : تكرار فوق إدخالات باستخدام حلقة For-Each.

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

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

لاحظ أن حلقة For-Each تم تقديمها في Java 5 ، بحيث تعمل هذه الطريقة فقط في إصدارات أحدث من اللغة. كما ستقوم حلقة For-Each برمي NullPointerException إذا حاولت التكرار فوق خريطة خالية ، لذا قبل التكرار ، يجب أن تتحقق دائمًا من المراجع الفارغة.

الطريقة الثانية : التكرار فوق المفاتيح أو القيم باستخدام حلقة For-Each.

إذا كنت تحتاج فقط إلى مفاتيح أو قيم من الخريطة ، فيمكنك التكرار عبر keySet أو القيم بدلاً من entrySet.

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

// Iterating over keys only
for (Integer key : map.keySet()) {
    System.out.println("Key = " + key);
}

// Iterating over values only
for (Integer value : map.values()) {
    System.out.println("Value = " + value);
}

توفر هذه الطريقة ميزة أداء بسيطة على التكرار (حوالي 10٪ أسرع) وأكثر نظافة.

الطريقة الثالثة : التكرار باستخدام Iterator.

استخدام Generics:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry<Integer, Integer> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

بدون Generics:

Map map = new HashMap();
Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry entry = (Map.Entry) entries.next();
    Integer key = (Integer)entry.getKey();
    Integer value = (Integer)entry.getValue();
    System.out.println("Key = " + key + ", Value = " + value);
}

يمكنك أيضًا استخدام نفس الأسلوب للتكرار عبر keySet أو القيم.

قد تبدو هذه الطريقة زائدة عن الحاجة ، ولكن لها مزاياها الخاصة. أولاً ، إنها الطريقة الوحيدة للتكرار على خريطة في الإصدارات القديمة من Java. الميزة الهامة الأخرى هي أنها الطريقة الوحيدة التي تسمح لك بإزالة الإدخالات من الخريطة أثناء التكرار عن طريق استدعاء iterator.remove() . إذا حاولت القيام بذلك خلال For-each التكرار سوف تحصل على "نتائج غير متوقعة" وفقا Javadoc .

من وجهة نظر أداء هذه الطريقة تساوي كل التكرار.

الطريقة الرابعة : التكرار على المفاتيح والبحث عن القيم (غير فعالة).

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println("Key = " + key + ", Value = " + value);
}

قد يبدو هذا بديلاً أنظفًا للطريقة رقم 1 ، ولكنه عمليًا بطيء جدًا وغير كفء لأن الحصول على قيم بواسطة مفتاح قد يكون مستهلكًا للوقت (هذه الطريقة في تطبيقات خرائط مختلفة تكون أبطأ بنسبة 20٪ -200٪ من الطريقة رقم 1 ). إذا كان لديك FindBugs مثبتًا ، فستكتشف هذا وتحذيرك من التكرار غير الفعال. يجب تجنب هذه الطريقة.

استنتاج:

إذا كنت تحتاج فقط إلى مفاتيح أو قيم من الخريطة ، فاستخدم الطريقة رقم 2. إذا كنت عالقاً في الإصدار القديم من Java (أقل من 5) أو تخطط لإزالة الإدخالات أثناء التكرار ، فيجب عليك استخدام الطريقة رقم 3. خلاف ذلك طريقة استخدام # 1.


for (Map.Entry<String, String> item : params.entrySet()) {
    String key = item.getKey();
    String value = item.getValue();
}

أكثر ذكاء:

for (String key : hashMap.keySet()) {
    System.out.println("Key: " + key + ", Value: " + map.get(key));
}

يعتمد على. إذا كنت تعرف أنك ستحتاج إلى كل مفتاح وقيمة كل إدخال ، ثم انتقل من خلال entrySet . إذا كنت تحتاج فقط إلى القيم ، فهناك طريقة values() . وإذا كنت بحاجة فقط إلى المفاتيح ، استخدم keyset() .

قد يكون من الممارسات السيئة تكرار كل المفاتيح ، ثم داخل الحلقة دائمًا map.get(key) للحصول على القيمة. إذا كنت تفعل ذلك ، فإن الخيار الأول الذي كتبته هو لك.


إذا كنت مهتمًا بالمفاتيح فقط ، فيمكنك التكرار من خلال keySet() للخريطة:

Map<String, Object> map = ...;

for (String key : map.keySet()) {
    // ...
}

إذا كنت تحتاج فقط إلى القيم ، فاستخدم values() :

for (Object value : map.values()) {
    // ...
}

وأخيرًا ، إذا كنت تريد المفتاح والقيمة ، فاستخدم entrySet() :

for (Map.Entry<String, Object> entry : map.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();
    // ...
}

تحذير واحد: إذا كنت ترغب في إزالة العناصر منتصف التكرار ، فسوف تحتاج إلى القيام بذلك عن طريق Iterator (انظر الإجابة karim79 ). ومع ذلك ، تغيير قيم العنصر على ما يرام (انظر Map.Entry ).


في مثل هذه الحالات ، من المفترض أن تكون الخدعة الشائعة هي العودة إلى الوراء:

for(int i = l.size() - 1; i >= 0; i --) {
  if (l.get(i) == 5) {
    l.remove(i);
  }
}

ومع ذلك ، أنا أكثر من سعيد أن لديك طرق أفضل في Java 8 ، على سبيل المثال removeIf أو filter على مجموعات البث.





java loops hashmap iteration