중복 키가있는지도를 갖고 싶습니다.
많은지도 구현이 있다는 것을 알고 있습니다 (Eclipse는 약 50 개를 보여줍니다). 그래서 이것을 허용하는 것이 있어야합니다. 이 작업을 수행하는 자신의지도를 작성하는 것이 쉽다는 것을 알고 있지만 기존 솔루션을 사용하고 싶습니다.
커먼즈 컬렉션이나 구글 컬렉션에있는 것일까 요?
중복 키가있는지도를 갖고 싶습니다.
많은지도 구현이 있다는 것을 알고 있습니다 (Eclipse는 약 50 개를 보여줍니다). 그래서 이것을 허용하는 것이 있어야합니다. 이 작업을 수행하는 자신의지도를 작성하는 것이 쉽다는 것을 알고 있지만 기존 솔루션을 사용하고 싶습니다.
커먼즈 컬렉션이나 구글 컬렉션에있는 것일까 요?
답변:
당신은 멀티 맵을 찾고 있으며, 실제로 commons-collections와 Guava는 여러 가지 구현을 가지고 있습니다. 멀티 맵은 키당 값 컬렉션을 유지하여 여러 키를 허용합니다. 즉, 단일 객체를 맵에 넣을 수 있지만 컬렉션을 검색합니다.
Java 5를 사용할 수 있다면 Multimap
제네릭을 인식 하는 Guava를 선호합니다 .
com.google.common.collect.HashMultimap
가 있습니다. 쓸모없는 deserialized 인스턴스는보고 할 가치가있는 버그라고 생각합니다. readObject
writeObject
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;
(주석에 쓴 것처럼) 키-값 쌍 목록에 대해 반복하려면 목록 또는 배열이 더 좋습니다. 먼저 키와 값을 결합하십시오.
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
내 실수로부터 배우십시오 ... 이것을 스스로 구현하지 마십시오. 구아바 멀티 맵은 갈 길입니다.
멀티 맵에 필요한 일반적인 개선 사항은 중복 키-값 쌍을 허용하지 않는 것입니다.
구현에서 이것을 구현 / 변경하는 것은 성 가실 수 있습니다.
구아바에서는 다음과 같이 간단합니다.
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 개체로 대체하여 다른 값 매핑에 대한 단일 키를 유지하는 데 도움이되었습니다.
멋진 라이브러리가 필요하지 않습니다. 맵은 고유 키로 정의되므로 구부리지 말고 목록을 사용하십시오. 스트림은 강력합니다.
import java.util.AbstractMap.SimpleImmutableEntry;
List<SimpleImmutableEntry<String, String>> nameToLocationMap = Arrays.asList(
new SimpleImmutableEntry<>("A", "A1"),
new SimpleImmutableEntry<>("A", "A2"),
new SimpleImmutableEntry<>("B", "B1"),
new SimpleImmutableEntry<>("B", "B1"),
);
그리고 그게 다야. 사용 예 :
List<String> allBsLocations = nameToLocationMap.stream()
.filter(x -> x.getKey().equals("B"))
.map(x -> x.getValue())
.collect(Collectors.toList());
nameToLocationMap.stream().forEach(x ->
do stuff with: x.getKey()...x.getValue()...
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;
}
}
1, Map<String, List<String>> map = new HashMap<>();
이 장황한 솔루션에는 여러 가지 단점이 있으며 오류가 발생하기 쉽습니다. 모든 값에 대해 컬렉션을 인스턴스화하고, 값을 추가하거나 제거하기 전에 그 존재를 확인하고, 값이 남아 있지 않을 때 수동으로 삭제하는 등의 작업이 필요함을 의미합니다.
2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface
그런 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() .....
}
중복 키를 사용하여 맵을 구현하려는 컨텍스트를 설명해 주시겠습니까? 더 나은 해결책이있을 수 있다고 확신합니다. 지도는 정당한 이유로 고유 키를 유지하기위한 것입니다. 정말로하고 싶다면; 충돌 완화 기능이 있고 동일한 키로 여러 항목을 유지할 수있는 간단한 사용자 지정 맵 클래스를 작성하여 항상 클래스를 확장 할 수 있습니다.
참고 : 충돌 키가 "항상"고유 한 집합으로 변환되도록 충돌 완화 기능을 구현해야합니다. 객체 해시 코드 등으로 키를 추가하는 것과 같은 간단한 것입니까?
완료하기 위해 Apache Commons Collections에는 MultiMap도 있습니다. 물론 단점은 Apache Commons가 Generics를 사용하지 않는다는 것입니다.
약간의 해킹으로 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<>();