web-dev-qa-db-ja.com

Javaの値でマップから要素を削除する最も簡単な方法は何ですか?

Javaの値でマップから要素を削除する最も簡単な方法は何ですか?

現在、私は使用しています:

    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);
    }
34
Supertux

双方向マップ( commons-collections および googleコレクション を使用)を使用しないと、マップの反復処理が必要になります

26
Kevin

正確で高速なワンライナーは、実際には次のようになります。

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

上記の例のほとんどがvalueObjectが一意であると想定しているのは奇妙なことです。

72
Robbert

これが1行のソリューションです。

map.values().remove(valueToRemove);

JDKコレクションコードが大幅に最適化されているため、独自のイテレータを定義するよりもおそらく高速です。

他の人が述べたように、バイマップはより多くのメモリを必要とし、ポピュレートに時間がかかりますが、値の削除が高速になります。また、値が一意である場合にのみビマップが機能します。これは、コードに当てはまる場合とそうでない場合があります。

24
Jared Levy
map.values().removeAll(Collections.singleton(null));

HashMap <String、String>?から「Null」値をフィルタリングする方法 への参照、Java 8:

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

逆マップがない場合は、イテレーターを使用します。

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.
    }
}
11

値コレクションを使用すると、そのコレクションに変更が加えられると、変更がマップに反映されるため、常に使用できます。したがって、Map.values()。remove(valueToRemove)を呼び出した場合、それは機能するはずです-ただし、そのループを使用した場合よりもパフォーマンスが向上するかどうかはわかりません。 1つのアイデアは、バッキングコレクションが常に値でソートされるようにマップクラスを拡張またはオーバーライドすることです。これにより、値に対してバイナリ検索を実行できるようになり、より高速になります。

編集:これは本質的にAlconの答えと同じですが、entrySetはまだキーで順序付けられているため、彼が機能するとは思わない-その場合、値で.remove()を呼び出すことはできません。

また、これは、値が一意であると想定されていること、またはマップから重複を削除することも想定していることです。

7
Corazu

私はこれを使用します

 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");

編集:オブジェクトは値ではなく「ポインター」によって参照されるため。

N

6
Nico

DomainObjからキーを把握する方法がない場合、それを改善する方法はわかりません。値からキーを取得する組み込みメソッドがないため、haveを使用してマップを反復処理します。

これが常にあなたがしていることである場合、2つのマップ(string-> DomainObjおよびDomainObj-> Key)を維持できます。

4
Nader Shirazie

他のほとんどのポスターが言っているように、ハッシュテーブル値のリスト全体に関係なく見なければならないので、一般にO(N)操作です。@ tacklineには正しい解決策がありますメモリ使用量をO(1)(私は彼にそのための賛成票を与えた)に保つため。

他のオプションは、速度のためにメモリ空間を犠牲にすることです。マップのサイズが適切であれば、2つのマップを並行して保存できます。

マップがある場合は、それに並行してマップを維持します。一方のマップで挿入/削除するときは、もう一方のマップでも実行します。スペースが無駄になり、DomainObjの「hashCode」メソッドが適切に記述されていることを確認する必要がありますが、除去時間はO(N)= = O(1)どちらの方向でも一定時間でキー/オブジェクトマッピングを検索できるため。

一般的に最善の解決策ではありませんが、一番の懸念事項が速度である場合、これはおそらくあなたが得ようとしているのと同じくらい速いと思います。

====================補遺:これは、本質的に@msaeedがサードパーティのライブラリを除いて示唆したものです。

2

イテレータの短い使用法は、values()イテレータを使用することです。

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

この状況はめったに発生しませんが、非常に役立ちます。 org.Apache.commons.collectionsBidiMapを優先します。

1
DKSRathore

これがアプリのライフタイムで一度しか発生しないとは思いません。

したがって、私がすることは、そのマップに追加されたオブジェクトへの参照を維持する責任を別のオブジェクトに委任することです。

そのため、次に削除する必要があるときは、その「逆マップ」を使用します...

 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 );
           }
     }
  }

これは反復よりもはるかに高速です。

明らかに、それらの同期を維持する必要があります。しかし、マップの状態を担当する1つのオブジェクトを持つようにコードをリフレクトする場合、それほど難しくないはずです。

OOPには状態と動作を持つオブジェクトがあります。データがあらゆる場所で変数を通過している場合、オブジェクト間に不要な依存関係を作成していることに注意してください。

はい、コードを修正するのに時間がかかりますが、修正に費やす時間は、将来の多くの頭痛の種を節約します。考えてみてください。

0
OscarRyz