source

중복된 키를 사용한 맵 구현

manysource 2022. 10. 15. 09:59

중복된 키를 사용한 맵 구현

열쇠가 중복된 지도를 원합니다.

많은 맵 실장(Eclipse는 50개 정도 표시)이 있는 것을 알고 있기 때문에, 이것을 가능하게 하는 맵 실장은 분명히 있을 것입니다.이 기능을 하는 지도를 직접 작성하는 것이 쉽다는 것을 알지만, 기존 솔루션을 사용하는 것이 좋습니다.

일반 컬렉션이나 구글 컬렉션 같은 거?

멀티맵을 찾고 있으며, 실제로 Commons-Collections와 Guava 모두 이를 위한 몇 가지 구현이 있습니다.멀티맵에서는 키당 값의 컬렉션을 유지함으로써 여러 키를 사용할 수 있습니다.즉, 맵에 단일 개체를 넣을 수 있지만 컬렉션을 가져올 수 있습니다.

Java 5를 사용할 수 있다면 Generics 대응 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]

참고: 라이브러리 파일을 Import해야 합니다.

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을 사용할 수도 있지만, 중복 키를 사용하는 것은 마음에 들지 않습니다.

키와 값 쌍의 리스트를 코멘트에 기재한 대로 반복하는 경우는, 리스트 또는 배열을 사용하는 것이 좋습니다.먼저 키와 값을 조합합니다.

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)
{
   ...
}

는 맵 목록으로 할 수 .List<Map.Entry<K,V>>외부 라이브러리나 Map의 새로운 구현을 사용할 필요가 없습니다.는 다음과할 수 .Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);

[2021년 6월]

  1. org.springframework.springfrack멀티밸류맵

  2. commons.apache.org - org.http.collections 4

내 실수에서 배우다...혼자 실행하지 말아주세요.Guava multimap이 좋은 방법입니다.

멀티맵에서 일반적으로 필요한 확장 기능은 중복된 키와 값의 쌍을 허용하지 않는 것입니다.

구현에서 이를 구현/변경하는 것은 번거로울 수 있습니다.

Guava에서는 다음과 같이 단순합니다.

HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();

ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();

고급 립은 필요 없습니다.맵은 고유한 키로 정의되므로 맵을 구부리지 말고 목록을 사용하십시오.시냇물이 세다.

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()...

각 키를 다른 키와 동등하지 않은 것으로 취급하기 위해 TreeMap을 커스텀 Comparator와 함께 사용할 수 있습니다.Linked Hash Map과 마찬가지로 맵의 삽입 순서도 유지됩니다.따라서 최종 결과는 중복 키를 허용하는 Linked Hash Map과 같습니다.

이것은, 서드 파티의 의존 관계나 멀티 맵의 복잡함 없이, 매우 심플한 실장입니다.

import java.util.Map;
import java.util.TreeMap;

...
...

//Define a TreeMap with a custom Comparator
Map<Integer, String> map = new TreeMap<>((a, b) -> 1); // See notes 1 and 2

//Populate the map
map.put(1, "One");
map.put(3, "Three");
map.put(1, "One One");
map.put(7, "Seven");
map.put(2, "Two");
map.put(1, "One One One");
    
//Display the map entries:
map.entrySet().forEach(System.out::println);

//See note number 3 for the following:
Map<Integer, String> sortedTreeMap = map.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .collect(Collectors.toMap(
                Map.Entry::getKey, Map.Entry::getValue,
                (x, y) -> x, () -> new TreeMap<>((a, b) -> 1)
             ));
//Display the entries of this sorted TreeMap: 
sortedTreeMap.entrySet().forEach(System.out::println);

    
...

주의:

  1. 여기서 비교기 정의에서 1 대신 임의의 양의 정수를 사용할 수도 있습니다.
  2. 대신 음의 정수를 사용하면 맵의 삽입 순서가 반대로 됩니다.
  3. 이 맵을 키(TreeMap의 기본 동작)에 따라 정렬하는 경우에도 현재 맵에서 이 작업을 수행할 수 있습니다.

이 문제에 대해서는 조금 다른 변형이 있었습니다.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 );
        }
}

위 코드에서 키 프레임은각 줄에 있는 입력 파일의 첫 번째 문자열에서 ID를 읽어냅니다.frameTypeHash 값은 나머지 행을 분할하여 구성되며, 원래 String 개체로 저장되었습니다.이 기간 동안 파일은 동일한 프레임과 관련된 여러 줄(다른 값을 가진)을 가지기 시작했습니다.ID 키이므로 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;
        }
    }
 1, Map<String, List<String>> map = new HashMap<>();

이 장황한 솔루션은 여러 가지 결점이 있으며 오류가 발생하기 쉽습니다.즉, 모든 값에 대해 컬렉션을 인스턴스화하고, 값을 추가 또는 삭제하기 전에 컬렉션이 존재하는지 확인하며, 값이 남아 있지 않으면 수동으로 삭제해야 합니다.

2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface 

java-map-syslog-keys

이러한 멀티맵의 영향은 어떻습니까?

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를 사용하지 않는다는 것이다.

Bit Hack을 사용하면 중복된 키로 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<>();

언급URL : https://stackoverflow.com/questions/1062960/map-implementation-with-duplicate-keys