簡體   English   中英

在Java中通過值從Map中刪除元素的最快方法是什么?

[英]What's the quickest way to remove an element from a Map by value in Java?

在Java中通過值從Map中刪除元素的最快方法是什么?

目前我正在使用:

    DomainObj valueToRemove = new DomainObj();
    String removalKey = null;

    for (Map.Entry<String, DomainObj> entry : map.entrySet()) {
        if (valueToRemove.equals(entry.getValue())) {
            removalKey = entry.getKey();
            break;
        }
    }

    if (removalKey != null) {
        map.remove(removalKey);
    }

正確而快速的單線實際上是:

while (map.values().remove(valueObject));

有點奇怪的是,上面的大多數例子都假設valueObject是唯一的。

如果不使用雙向地圖( 公共集合谷歌集合都有它們),你就會陷入迭代地圖的困境

這是一線解決方案:

map.values().remove(valueToRemove);

這可能比定義自己的迭代器更快,因為JDK集合代碼已經過顯着優化。

正如其他人所提到的,bimap將有更快的值刪除,但它需要更多的內存並且需要更長的時間來填充。 此外,bimap僅在值唯一時才有效,這可能是您的代碼中的情況,也可能不是。

如果你沒有反向映射,我會選擇迭代器。

DomainObj valueToRemove = new DomainObj();

for (
    Iterator<Map.Entry<String, DomainObj>> iter = map.entrySet().iterator();
    iter.hasNext();
) {
    Map.Entry<String, DomainObj> entry = iter.next();
    if (valueToRemove.equals(entry.getValue())) {
        iter.remove();
        break; // if only want to remove first match.
    }
}
map.values().removeAll(Collections.singleton(null));

參考如何從HashMap <String,String>過濾“Null”值? ,我們可以為java 8做以下事情:

map.values().removeIf(valueToRemove::equals);

您始終可以使用值集合,因為對該集合所做的任何更改都將導致更改反映在地圖中。 因此,如果您要調用Map.values()。remove(valueToRemove)應該可以工作 - 雖然我不確定您是否會看到比使用該循環更好的性能。 一種想法是擴展或覆蓋map類,這樣后備集合總是按值排序 - 這將使您能夠對值進行二進制搜索,這可能更快。

編輯:這與Alcon的答案基本相同,除了我認為他的工作沒有用,因為entrySet仍然按鍵排序 - 在這種情況下你不能用值調用.remove()。

這也假設該值應該是唯一的,或者您也希望從Map中刪除任何重復項。

我會用這個

 Map x = new HashMap();
x.put(1, "value1");
x.put(2, "value2");
x.put(3, "value3");
x.put(4, "value4");
x.put(5, "value5");
x.put(6, "value6");

x.values().remove("value4");

編輯:因為對象由“指針”引用而不是由值引用。

ñ

如果你無法從DomainObj中找出密鑰,那么我看不出你如何改進它。 沒有內置方法從值中獲取密鑰,因此您必須遍歷地圖。

如果這是您一直在做的事情,您可能會維護兩個映射(string-> DomainObj和DomainObj-> Key)。

像大多數其他海報所說的那樣,它通常是一個O(N)操作,因為你將不得不查看整個哈希表值列表。 @tackline有一個正確的解決方案,可以將內存使用量保持在O(1)(我給了他一個投票權)。

你的另一個選擇是為了速度而犧牲內存空間。 如果地圖的大小合理,則可以並行存儲兩個地圖。

如果您有Map,則保持與其並行的Map。 在一個地圖上插入/刪除時,也可以在另一個地圖上執行。 雖然這很丑陋,因為你浪費了空間,你必須確保DomainObj的“hashCode”方法寫得正確,但你的刪除時間從O(N)下降到O(1),因為你可以查找密鑰/ object在任意方向上以恆定時間映射。

通常不是最好的解決方案,但如果你最關心的是速度,我認為這可能和你想要的一樣快。

====================附錄:這基本上是@msaeed所建議的,只是沒有第三方庫。

迭代器的較短用法是使用values()迭代器。

DomainObj valueToRemove = new DomainObj();
for (Iterator<DomainObj> it = map.values().iterator(); it.hasNext();)) {
        if (valueToRemove.equals(it.next())) {
                it.remove();
                break;
        }
}

我們知道這種情況很少出現,但非常有幫助。 我更喜歡org.apache.commons.collections的 BidiMap

我不認為這會在您的應用的生命周期中發生一次。

所以我要做的是委托另一個對象負責維護對添加到該映射的對象的引用。

所以下次你需要刪除它時,你會使用“反向地圖”......

 class MapHolder { 

     private Map<String, DomainObj> originalMap;
     private Map<DomainObj,String> reverseMap;

     public void remove( DomainObj value ) {
           if ( reverseMap.contains( value ) ) { 
                 originalMap.remove( reverseMap.get( value ) );
                 reverseMap.remove( value );
           }
     }
  }

這比迭代要快得多。

顯然你需要讓它們保持同步。 但是如果你重新編寫代碼以使一個對象負責地圖的狀態,那就不應該那么難了。

請記住,在OOP中,我們擁有具有狀態和行為的對象。 如果您的數據遍布整個變量,則會在對象之間創建不必要的依賴關系

是的,您需要一些時間來糾正代碼,但是糾正它的時間將在未來為您節省很多麻煩。 想一想。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM