【问题标题】:Access and modify the next entry set while iterating a map in Java在 Java 中迭代映射时访问和修改下一个条目集
【发布时间】:2019-07-08 02:01:33
【问题描述】:

在处理问题陈述时,我需要访问 Map 的下一个 Entry 并根据条件修改下一个条目值。

我一直在考虑这里提供的解决方案:How to get the previous key/value and the next key/value in Maps 我可以使用NavigableMap 访问higherEntry,但它会抛出:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractMap$SimpleImmutableEntry.setValue(AbstractMap.java:797)

这是完全可以理解的。这是代码sn-p

for (Map.Entry<Character, Integer> current : myMap.entrySet()) {

    Map.Entry<Character, Integer> next = myMap.higherEntry(current.getKey());

    if (current.getValue() == next.getValue()) {
        // Code block
    } else if (current.getValue() > next.getValue()) {
        // Code block
    } else {
        next.setValue(1); // Line that throws Exception
    }
}

如何遍历Map,在需要时访问和修改下一个条目?

【问题讨论】:

  • 为什么不直接遍历键列表,然后使用键检索值进行比较,然后使用Map.put() 覆盖它?您正在使用的Map 的实现对条目使用SimpleImmutableEntry 实现,这不允许您使用setValue()

标签: java dictionary collections


【解决方案1】:

您可以使用普通的 for 循环并跟踪索引,而不是使用增强的 for 循环。这很棘手,因为您需要一种访问下一个条目的方法,这取决于您是否使用Map 的有序实现(如LinkedHashMap)。如果您没有使用LinkedHashMap 或一些类似的有序映射,这将不一致,并且条目可能会乱序。假设您正在使用有序映射,您可以首先将条目集转换为数组并从那里开始。这看起来像 Map.Entry&lt;Character, Integer&gt;[] entries = myMap.entrySet().stream().toArray(Map.Entry[]::new); 然后,您可以在这个数组中使用 for 循环。

for (int i = 0; i < entries.length-1; i++) {
    Map.Entry<Character, Integer> current = entries[i];
    Map.Entry<Character, Integer> next = entries[i+1];
    //code that does stuff
}

【讨论】:

    【解决方案2】:

    TreeMap.higherEntry 返回一个 不可变 条目,这解释了您所看到的 UnsupportedOperationException

    //exportEntry is being called by TreeMap.higherEntry(K)
    static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) {
        return (e == null) ? null :
            new AbstractMap.SimpleImmutableEntry<>(e);
    }
    

    一种可能的解决方案/解决方法是将更新的条目收集到地图中,然后在循环后修改原始地图:

    Map<Character, Integer> updates = new HashMap<>();
    
    for (Map.Entry<Character, Integer> current : myMap.entrySet()) {
    
        Map.Entry<Character, Integer> next = myMap.higherEntry(current.getKey());
    
        if(null != next) {
            if (current.getValue() == next.getValue()) {
            } else if (current.getValue() > next.getValue()) {
            } else {
                updates.put(next.getKey(), 1); // entry to be updated
            }
        }
    }
    
    myMap.putAll(updates);
    

    请注意,我添加了一个空检查,因为 myMap.higherEntry 可能会返回 null

    【讨论】:

      【解决方案3】:
              Map.Entry<String, Integer> next = myMap.higherEntry(current.getKey());
      
              if(next != null)
              {
                  if (current.getValue() == next.getValue())
                  {
                      //Code block
                  }
                  else if (current.getValue() > next.getValue()) {
                      //Code block
                  }
      
                  else {
                      myMap.put(current.getKey(), 1); 
      
                  }
              }
      

      【讨论】:

        【解决方案4】:

        higherEntry 方法返回一个不可变的条目,但您的代码也缺少对没有更高条目的情况的处理。另一方面,迭代器返回的下一个条目无论如何都是正确的条目(如果有的话),因此可以手动使用Iterator 来完成,如下所示:

        Iterator<Map.Entry<Character, Integer>> it = myMap.entrySet().iterator();
        if(it.hasNext()) {
            for(Map.Entry<Character, Integer> current=it.next(), next; it.hasNext(); current=next) {
                next = it.next();
                // don't compare Integer objects via ==, use equals
                if (current.getValue().equals(next.getValue())) {
                    // Code block
                } else if (current.getValue() > next.getValue()) {
                    // Code block
                } else {
                    next.setValue(1);
                }
            }
        }
        

        一个“不那么干净”但相当简单的替代方案是

        Map.Entry<Character, Integer> current = null;
        for(Map.Entry<Character, Integer> next: myMap.entrySet()) {
            if(current != null) {
                if (current.getValue().equals(next.getValue())) {
                    // Code block
                } else if (current.getValue() > next.getValue()) {
                    // Code block
                } else {
                    next.setValue(1);
                }
            }
            current = next;
        }
        

        【讨论】:

          猜你喜欢
          • 2010-10-15
          • 1970-01-01
          • 2012-08-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-13
          • 1970-01-01
          相关资源
          最近更新 更多