중복 키로 구현 매핑
중복 키가있는지도를 갖고 싶습니다.
많은지도 구현이 있다는 것을 알고 있습니다 (Eclipse는 약 50 개를 보여줍니다). 그래서 이것을 허용하는 것이 있어야합니다. 이 작업을 수행하는 자신의지도를 작성하는 것이 쉽다는 것을 알고 있지만 기존 솔루션을 사용하고 싶습니다.
커먼즈 컬렉션이나 구글 컬렉션에있는 것일까 요?
당신은 멀티 맵을 찾고 있으며, 실제로 commons-collections와 Guava는 여러 가지 구현을 가지고 있습니다. 멀티 맵은 키당 값 컬렉션을 유지하여 여러 키를 허용합니다. 즉, 단일 객체를 맵에 넣을 수 있지만 컬렉션을 검색합니다.
Java 5를 사용할 수 있다면 Multimap
제네릭을 인식 하는 Guava를 선호합니다 .
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의 값에 대한 값 배열을 전달하여 중복 키를 시뮬레이션 할 수 있으며 사용할 데이터를 결정하는 것은 사용자에게 달려 있습니다.
중복 키에 대한 아이디어가 마음에 들지 않지만 MultiMap을 사용할 수도 있습니다 .
(주석에 쓴 것처럼) 키-값 쌍 목록에 대해 반복하려면 List 또는 배열이 더 좋습니다. 먼저 키와 값을 결합하십시오.
public class Pair
{
public Class1 key;
public Class2 value;
public Pair(Class1 key, Class2 value)
{
this.key = key;
this.value = value;
}
}
Class1 및 Class2를 키 및 값에 사용할 유형으로 바꿉니다.
이제 배열이나 목록에 넣고 반복 할 수 있습니다.
Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
...
}
commons.apache.org
MultiValueMap class
이 문제는 맵 항목 목록으로 해결할 수 있습니다 List<Map.Entry<K,V>>
. 외부 라이브러리 나 새로운 Map 구현을 사용할 필요가 없습니다. 다음과 같이 맵 항목을 만들 수 있습니다.Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);
내 실수로부터 배우십시오 ... 이것을 스스로 구현하지 마십시오. 구아바 멀티 맵은 갈 길입니다.
멀티 맵에 필요한 일반적인 개선 사항은 중복 키-값 쌍을 허용하지 않는 것입니다.
구현에서 이것을 구현 / 변경하는 것은 성 가실 수 있습니다.
구아바에서는 다음과 같이 간단합니다.
HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();
ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();
이 문제에 대해 약간 다른 변형이있었습니다. 두 개의 다른 값을 동일한 키에 연결해야했습니다. 다른 사람들에게 도움이 될 수 있도록 여기에 게시하기 만하면 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 );
}
}
위의 코드에서 key frameID는 각 줄에있는 입력 파일의 첫 번째 문자열에서 읽히고, frameTypeHash의 값은 나머지 줄을 분할하여 구성되며 파일이 여러 줄로 시작된 기간 동안 원래 String 개체로 저장되었습니다. 다른 값으로) 동일한 frameID 키와 연결되어 있으므로 frameTypeHash는 값으로 마지막 줄을 덮어 씁니다. String 개체를 값 필드로 다른 HashMap 개체로 대체하여 다른 값 매핑에 대한 단일 키를 유지하는 데 도움이되었습니다.
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;
}
}
Could you also explain the context for which you are trying to implement a map with duplicate keys? I am sure there could be a better solution. Maps are intended to keep unique keys for good reason. Though if you really wanted to do it; you can always extend the class write a simple custom map class which has a collision mitigation function and would enable you to keep multiple entries with same keys.
Note: You must implement collision mitigation function such that, colliding keys are converted to unique set "always". Something simple like, appending key with object hashcode or something?
just to be complete, Apache Commons Collections also has a MultiMap. The downside of course is that Apache Commons does not use Generics.
With a bit hack you can use HashSet with duplicate keys. WARNING: this is heavily HashSet implementation dependant.
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);
}
}
If there are duplicate keys then a key may correspond to more than one value. The obvious solution is to map the key to a list of these values.
For example in 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
I used this:
java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();
1, Map<String, List<String>> map = new HashMap<>();
this verbose solution has multiple drawbacks and is prone to errors. It implies that we need to instantiate a Collection for every value, check for its presence before adding or removing a value, delete it manually when no values are left, etcetera.
2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface
what about such a MultiMap 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() .....
}
참고URL : https://stackoverflow.com/questions/1062960/map-implementation-with-duplicate-keys
'programing tip' 카테고리의 다른 글
Visual Studio에서 디버그와 릴리스의 차이점은 무엇입니까? (0) | 2020.08.12 |
---|---|
Elasticsearch 대 Cassandra 대 Cassandra를 사용한 Elasticsearch (0) | 2020.08.12 |
문자열의 줄을 반복합니다. (0) | 2020.08.12 |
Rmarkdown에 \ newpage를 현명하게 추가하는 방법은 무엇입니까? (0) | 2020.08.12 |
.h.gch 파일이란 무엇입니까? (0) | 2020.08.12 |