2016-04-05 69 views
2

我想从LinkedHashMap中删除所有条目,这些条目是使用给定键值添加到条目之后的。如何高效地从Java中的LinkedHashMap中删除条目?

我的第一个尝试是:

LinkedHashMap<String, SomeObject> var = new LinkedHashMap<String, SomeObject>(); 

public void removeEntriesAfter(String key) { 
    boolean deleteEntries = false; 
    for (String currentKey : var.keySet()) { 
    if(deleteEntries) { 
     var.remove(currentKey); 
    } else { 
     if(key.equalsIgnoreCase(currentKey)) { 
     // Do not remove the current entry 
     deleteEntries = true; 
     } 
    } 
    } 
} 

但后来我收到了java.util.ConcurrentModificationException

我的第二个想法是首先确定键,然后将其删除。

public void removeEntriesAfter(String key) { 
    boolean deleteEntries = false; 
    List<String> listOfEntriesToBeRemoved = new ArrayList<String>(); 

    // Determine entries to be deleted 
    for (String currentKey : var.keySet()) { 
    if(deleteEntries) { 
     listOfEntriesToBeRemoved.add(currentKey); 
    } else { 
     if(key.equalsIgnoreCase(currentKey)) { 
     // Do not remove the current entry 
     deleteEntries = true; 
     } 
    } 
    } 

    // Removed selected entries 
    for (String currentKey : listOfEntriesToBeRemoved) { 
    var.remove(currentKey); 
    } 
} 

这很有效,但我确信有一个更优雅/高效的方式来做到这一点。

+4

通过'm.keySet()。iterator()'获取键迭代器。调用'next()'直到你到达'key'。之后调用'remove()'/ next()'直到'hasNext()'返回false。 – aioobe

回答

2

要避免ConcurrentModificationException,您可以使用Iterator

Iterator<String> it = map.keySet().iterator(); 
while (it.hasNext()) 
    if (it.next().equalsIgnoreCase(currentKey)) 
     break; 
while (it.hasNext()) { 
    it.next(); 
    it.remove(); 
} 

如果你想要的高效的解决方案,这将是直来直去的第一个地方相应的条目。要做到这一点,你将不得不将小写键放入地图中(而不是放入任何旧字符串并使用equalsIgnoreCase进行比较)。然后,使用反射,您可以访问对应于currentKey.toLowerCase()Map.Entry对象,然后再次使用反射,您可以沿着通过地图的所有链接。如果没有反思,这些都是不可能的,因为对应于键的条目和条目之间的链接都不通过公共API公开。我不建议反思,因为如果LinkedHashMap的代码发生更改,您的代码在将来可能很容易中断。

+0

有趣的是,我认为'it.remove();'从'Iterator'而不是从'LinkedHashMap'中移除。这有点令人困惑,但似乎工作。 – Edward