重複キーを使用したマップの実装
-
21-08-2019 - |
質問
重複キーを含むマップが必要です。
多くのマップ実装があることはわかっています (Eclipse では約 50 個が表示されます)。したがって、これを可能にするものがきっとあるはずです。これを行う独自のマップを作成するのが簡単であることはわかっていますが、私はむしろ既存のソリューションを使用したいと考えています。
Commons-collections または google-collections にあるものでしょうか?
解決
あなたはマルチマップを探している、と確かに両方コモンズ - コレクションとグァバは、そのためのいくつかの実装を持っています。 multimapのは、つまり、マップに単一のオブジェクトを置くことができ、キーごとの値のコレクションを維持することによって、複数のキーを可能にしていますが、コレクションを取得します。
あなたは、Java 5を使用することができた場合は、、私はグアバの<のhref = "https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/Multimap.htmlを好むだろう"REL =" noreferrer "> Multimap
のそれがジェネリック医薬品を意識しているよう。
他のヒント
私たちは、Googleのコレクション外部ライブラリに依存する必要はありません。あなたは、単に以下の地図を実装することができます:
Map<String, ArrayList<String>> hashMap = new HashMap<String, ArrayList>();
public static void main(String... arg) {
// Add data with duplicate keys
addValues("A", "a1");
addValues("A", "a2");
addValues("B", "b");
// View data.
Iterator it = hashMap.keySet().iterator();
ArrayList tempList = null;
while (it.hasNext()) {
String key = it.next().toString();
tempList = hashMap.get(key);
if (tempList != null) {
for (String value: tempList) {
System.out.println("Key : "+key+ " , Value : "+value);
}
}
}
}
private void addValues(String key, String value) {
ArrayList tempList = null;
if (hashMap.containsKey(key)) {
tempList = hashMap.get(key);
if(tempList == null)
tempList = new ArrayList();
tempList.add(value);
} else {
tempList = new ArrayList();
tempList.add(value);
}
hashMap.put(key,tempList);
}
微調整するコードを確認してください。
Multimap<Integer, String> multimap = ArrayListMultimap.create();
multimap.put(1, "A");
multimap.put(1, "B");
multimap.put(1, "C");
multimap.put(1, "A");
multimap.put(2, "A");
multimap.put(2, "B");
multimap.put(2, "C");
multimap.put(3, "A");
System.out.println(multimap.get(1));
System.out.println(multimap.get(2));
System.out.println(multimap.get(3));
出力されます:
[A,B,C,A]
[A,B,C]
[A]
の注:私たちは、ライブラリファイルをインポートする必要がありますの
。http://www.java2s.com/Code/Jar/g/ Downloadgooglecollectionsjar.htmする
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
や https://commons.apache.org/proper/commons-collections /download_collections.cgiする
import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;
あなたは、単にので、重複したキーをシミュレートし、定期的にHashMapの値の値の配列を渡すことができ、それがデータを使用するかを決定するためにあなた次第となります。
また、単にマルチマップに使用することができ、私は自分自身重複キーのアイデアを好きではないもののます。
、その後、リストや配列が良いはずです。まず、あなたのキーと値を組み合わせます:
public class Pair
{
public Class1 key;
public Class2 value;
public Pair(Class1 key, Class2 value)
{
this.key = key;
this.value = value;
}
}
あなたがキーと値に使用する種類のクラス1とクラス2を交換します。
これは、配列またはリストに入れ、それらを反復処理することができます:
Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
...
}
commons.apache.org
MultiValueMap class
この問題は、マップエントリList<Map.Entry<K,V>>
のリストを解決することができます。私たちはどちらも外部ライブラリや地図の新しい実装を使用する必要はありません。マップエントリは次のように作成することができます。
Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);
私の過ちから学ぶ...自分でこれを実装しないでください。 グアバのマルチマップを移動するための方法である。
multimapのに必要な一般的な増強は重複したキーと値のペアを禁止することである。
あなたの実装では、これを変更する/実装することはいらいらすることができます。
グァバそののような単純なます:
HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();
ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();
私は、この問題のわずかに異なるバリアントを持っていた:それは同じキーを持つ2つの異なる値を関連付けるために必要とされました。それは他の人を助け念のためにそれをここに掲示、私は値としてHashMapを導入しています:
/* @param frameTypeHash: Key -> Integer (frameID), Value -> HashMap (innerMap)
@param innerMap: Key -> String (extIP), Value -> String
If the key exists, retrieve the stored HashMap innerMap
and put the constructed key, value pair
*/
if (frameTypeHash.containsKey(frameID)){
//Key exists, add the key/value to innerHashMap
HashMap innerMap = (HashMap)frameTypeHash.get(frameID);
innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);
} else {
HashMap<String, String> innerMap = new HashMap<String, String>();
innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);
// This means the key doesn't exists, adding it for the first time
frameTypeHash.put(frameID, innerMap );
}
}
上記のコードでキーframeIDの各行に入力ファイルの最初の列から読み出され、frameTypeHashの値は、残りの行を分割することにより構成され、ファイルが有する開始時間の期間にわたって、本来文字列オブジェクトとして保存しました。 frameTypeHash値として最後の行で上書きされたように(異なる値を有する)複数の線は、同じframeIDのキーに関連付けられています。私は、これは別の値へのマッピングは、単一のキーを維持する上で助け、値フィールドとして別のHashMapオブジェクトとStringオブジェクトを置き換えます。
class DuplicateMap<K, V>
{
enum MapType
{
Hash,LinkedHash
}
int HashCode = 0;
Map<Key<K>,V> map = null;
DuplicateMap()
{
map = new HashMap<Key<K>,V>();
}
DuplicateMap( MapType maptype )
{
if ( maptype == MapType.Hash ) {
map = new HashMap<Key<K>,V>();
}
else if ( maptype == MapType.LinkedHash ) {
map = new LinkedHashMap<Key<K>,V>();
}
else
map = new HashMap<Key<K>,V>();
}
V put( K key, V value )
{
return map.put( new Key<K>( key , HashCode++ ), value );
}
void putAll( Map<K, V> map1 )
{
Map<Key<K>,V> map2 = new LinkedHashMap<Key<K>,V>();
for ( Entry<K, V> entry : map1.entrySet() ) {
map2.put( new Key<K>( entry.getKey() , HashCode++ ), entry.getValue());
}
map.putAll(map2);
}
Set<Entry<K, V>> entrySet()
{
Set<Entry<K, V>> entry = new LinkedHashSet<Map.Entry<K,V>>();
for ( final Entry<Key<K>, V> entry1 : map.entrySet() ) {
entry.add( new Entry<K, V>(){
private K Key = entry1.getKey().Key();
private V Value = entry1.getValue();
@Override
public K getKey() {
return Key;
}
@Override
public V getValue() {
return Value;
}
@Override
public V setValue(V value) {
return null;
}});
}
return entry;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("{");
boolean FirstIteration = true;
for ( Entry<K, V> entry : entrySet() ) {
builder.append( ( (FirstIteration)? "" : "," ) + ((entry.getKey()==null) ? null :entry.getKey().toString() ) + "=" + ((entry.getValue()==null) ? null :entry.getValue().toString() ) );
FirstIteration = false;
}
builder.append("}");
return builder.toString();
}
class Key<K1>
{
K1 Key;
int HashCode;
public Key(K1 key, int hashCode) {
super();
Key = key;
HashCode = hashCode;
}
public K1 Key() {
return Key;
}
@Override
public String toString() {
return Key.toString() ;
}
@Override
public int hashCode() {
return HashCode;
}
}
あなたはまた、あなたが重複したキーを持つマップを実装しようとしている状況を説明してもらえますか?私はよりよい解決策があるかもしれないと確信しています。マップは、正当な理由のためのユニークなキーを維持することを意図しています。あなたが本当にそれをやってみたかった場合けれども。あなたは常にクラスは、衝突軽減機能を有し、同じキーで複数のエントリを保つためにあなたを可能にする単純なカスタムマップクラスを記述拡張することができます。
注:あなたは衝突キーは「常に」のユニークなセットに変換され、というような衝突緩和機能を実装する必要があります。以下のような単純な何か、オブジェクトのハッシュコードか何かでキーを追加しますか?
補足として、Apache Commons Collections には マルチマップ. 。もちろん、欠点は、Apache Commons がジェネリックを使用しないことです。
ビットでは、あなたが重複するキーとのHashSetを使用することができますハック。警告:これは重くHashSetの実装依存です。
class MultiKeyPair {
Object key;
Object value;
public MultiKeyPair(Object key, Object value) {
this.key = key;
this.value = value;
}
@Override
public int hashCode() {
return key.hashCode();
}
}
class MultiKeyList extends MultiKeyPair {
ArrayList<MultiKeyPair> list = new ArrayList<MultiKeyPair>();
public MultiKeyList(Object key) {
super(key, null);
}
@Override
public boolean equals(Object obj) {
list.add((MultiKeyPair) obj);
return false;
}
}
public static void main(String[] args) {
HashSet<MultiKeyPair> set = new HashSet<MultiKeyPair>();
set.add(new MultiKeyPair("A","a1"));
set.add(new MultiKeyPair("A","a2"));
set.add(new MultiKeyPair("B","b1"));
set.add(new MultiKeyPair("A","a3"));
MultiKeyList o = new MultiKeyList("A");
set.contains(o);
for (MultiKeyPair pair : o.list) {
System.out.println(pair.value);
}
}
重複キーがある場合、キーは複数の値に対応してもよいです。明白な解決策は、これらの値のリストにキーをマップすることです。
のPython例えば:
map = dict()
map["driver"] = list()
map["driver"].append("john")
map["driver"].append("mike")
print map["driver"] # It shows john and mike
print map["driver"][0] # It shows john
print map["driver"][1] # It shows mike
私はこれを使用します:
java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();
1, Map<String, List<String>> map = new HashMap<>();
この冗長ソリューションは、複数の欠点があり、エラーを起こしやすいです。それ 我々はすべての値のためのコレクションをインスタンス化する必要があることを意味し、かどうかを確認 ときなし値を追加または削除する前に、その存在は、手動で削除します 値は、エトセトラ、残されています。
2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface
どのようなマルチマップのIMPLについてはどうですか?
public class MultiMap<K, V> extends HashMap<K, Set<V>> {
private static final long serialVersionUID = 1L;
private Map<K, Set<V>> innerMap = new HashMap<>();
public Set<V> put(K key, V value) {
Set<V> valuesOld = this.innerMap.get(key);
HashSet<V> valuesNewTotal = new HashSet<>();
if (valuesOld != null) {
valuesNewTotal.addAll(valuesOld);
}
valuesNewTotal.add(value);
this.innerMap.put(key, valuesNewTotal);
return valuesOld;
}
public void putAll(K key, Set<V> values) {
for (V value : values) {
put(key, value);
}
}
@Override
public Set<V> put(K key, Set<V> value) {
Set<V> valuesOld = this.innerMap.get(key);
putAll(key, value);
return valuesOld;
}
@Override
public void putAll(Map<? extends K, ? extends Set<V>> mapOfValues) {
for (Map.Entry<? extends K, ? extends Set<V>> valueEntry : mapOfValues.entrySet()) {
K key = valueEntry.getKey();
Set<V> value = valueEntry.getValue();
putAll(key, value);
}
}
@Override
public Set<V> putIfAbsent(K key, Set<V> value) {
Set<V> valueOld = this.innerMap.get(key);
if (valueOld == null) {
putAll(key, value);
}
return valueOld;
}
@Override
public Set<V> get(Object key) {
return this.innerMap.get(key);
}
@Override
etc. etc. override all public methods size(), clear() .....
}