중복 키를 HashMap에 넣으면 어떻게됩니까?


276

I가 동일한 키를 여러 번 전달하는 경우 HashMapput방법, 무슨 일이 원래 값은 어떻게됩니까? 그리고 값이 반복된다면 어떻게 될까요? 이것에 대한 문서를 찾지 못했습니다.

사례 1 : 키의 덮어 쓰기 값

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
System.out.println(mymap.get("1"));

우리는 얻는다 surely not one.

사례 2 : 중복 가치

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
// The following line was added:
mymap.put("1","one");
System.out.println(mymap.get("1"));

우리는 얻는다 one.

그러나 다른 가치는 어떻게됩니까? 나는 학생에게 기초를 가르치고 있었고 나는 이것을 물었다. 는 IS Map마지막 값이 참조 (그러나 메모리)되는 버킷 등?


7
BTW, 이것은 자카르타 컬렉션 클래스 ( commons.apache.org/collections )의 일부인 멀티 해시 맵을 보여줄 수있는 훌륭한 기회 입니다. 필요할 때 같은 키와 관련된 여러 값을 가질 수 있습니다.
John Munsch

답변:


303

정의에 따라, put명령은 맵에서 지정된 키와 연관된 이전 값을 대체합니다 (개념적으로 기본 유형의 배열 색인화 조작과 유사 함).

지도는 단순히 값에 대한 참조를 삭제합니다. 그 밖의 다른 객체에 대한 참조가 없으면 해당 객체는 가비지 수집 대상이됩니다. 또한 Java는 주어진 키와 관련된 이전 값을 반환하거나 null존재하지 않는 경우 반환하므로 필요한 내용을 확인하고 필요한 경우 참조를 유지할 수 있습니다.

자세한 내용은 여기 : HashMap Doc


고마워 Java 문서를 읽으면 명확하게 언급되지 않습니다. 나는 의사의 저자가 이것을 모든 해시 맵 구현의 암묵적 인 가정이라고 가정 한 것 같습니다.
앤드류 S

77

Map # put (K, V) 의 javadoc에서 실제로 답변을 찾을 수 있습니다 (실제로 무언가를 반환합니다).

public V put(K key,
             V value)

지정된 값을이 맵의 지정된 키와 연관시킵니다 (선택적 조작). 맵에 이전에이 키에 대한 맵핑이 포함 된 경우 이전 값이 지정된 값으로 대체됩니다. (지도 m는 을 반환하는 k경우에만 키에 대한 매핑을 포함한다고합니다 .)m.containsKey(k)true

파라미터 :
key -지정된 값을 관련 짓는 키.
value-지정된 키와 관련된 값.

반환 값 :
지정된 키에 관련한 값 또는 null매핑이 없었던 경우 key. (A null창은 표시 할 수있는 이전에 관련된지도를 null지정하여 key, 구현을 지원하는 경우 null의 값).

따라서 호출 할 때 반환 된 값을 할당하지 않으면 mymap.put("1", "a string")참조되지 않으므로 가비지 수집이 가능합니다.


3
반환 값 은 IS 이전 값 (또는 null그렇게, 그래,이 무슨 뜻인지 그냥 javadoc 내에서 위에 설명 된대로). 실제로 잘못 해석 될 수 있습니까?
Pascal Thivent

이것은 매우 도움이됩니다.
roottraveller

18

키의 이전 값이 삭제되고 새 값으로 바뀝니다.

키에 주어진 모든 값을 유지하려면 다음과 같이 구현하는 것이 좋습니다.

import org.apache.commons.collections.MultiHashMap;
import java.util.Set;
import java.util.Map;
import java.util.Iterator;
import java.util.List;
public class MultiMapExample {

   public static void main(String[] args) {
      MultiHashMap mp=new MultiHashMap();
      mp.put("a", 10);
      mp.put("a", 11);
      mp.put("a", 12);
      mp.put("b", 13);
      mp.put("c", 14);
      mp.put("e", 15);
      List list = null;

      Set set = mp.entrySet();
      Iterator i = set.iterator();
      while(i.hasNext()) {
         Map.Entry me = (Map.Entry)i.next();
         list=(List)mp.get(me.getKey());

         for(int j=0;j<list.size();j++)
         {
          System.out.println(me.getKey()+": value :"+list.get(j));
         }
      }
   }
}

1
이 솔루션은 더 이상 사용되지 않습니다. MultiHashMap은 java가 아닌 apache.commons.collections의 일부입니다.
wikimix

17

키 / 값 기능이며 여러 값에 대해 중복 키를 가질 수 없었
습니다. 예를 들어 값이 "1"인 값을 얻으려고 할 때 입력 된 키 에 속하는 값 중 실제 값 을 얻으려는 경우 그것은?!
이것이 모든 값에 대해 고유 한 키를 가지지 만 Java 표준 lib로 트릭을 가질 수있는 이유입니다.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class DuplicateMap<K, V> {

    private Map<K, ArrayList<V>> m = new HashMap<>();

    public void put(K k, V v) {
        if (m.containsKey(k)) {
            m.get(k).add(v);
        } else {
            ArrayList<V> arr = new ArrayList<>();
            arr.add(v);
            m.put(k, arr);
        }
    }

     public ArrayList<V> get(K k) {
        return m.get(k);
    }

    public V get(K k, int index) {
        return m.get(k).size()-1 < index ? null : m.get(k).get(index);
    }
}


그리고 당신은 이런 식으로 그것을 사용할 수 있습니다 :

    public static void main(String[] args) {
    DuplicateMap<String,String> dm=new DuplicateMap<>();
    dm.put("1", "one");
    dm.put("1", "not one");
    dm.put("1", "surely not one");
    System.out.println(dm.get("1"));
    System.out.println(dm.get("1",1));
    System.out.println(dm.get("1", 5));
}

인쇄 결과는 다음과 같습니다.

[one, not one, surely not one]
not one
null

좋은 답변입니다! 잘 했어. 문자 그대로 내 프로그래밍 수명을 절약하십시오.
Subin Babu

나에게도 감사합니다! 일반지도와 동일한 기능을 수행하기 위해 "제거"메소드를 추가해야했지만 훌륭하게 작동했습니다!
JGlass

1
@JGlass 당신의 환영하는 친구이지만, 이것은 기술적 인 해결책이 아닙니다. 이것은 당신이 자바 표준 lib로 할 수있는 일입니다. 기술적으로 문제가 발생하면 문제를 지켜봐야합니다. 키 / 가치 개념에 대한 문제이며, 문제에 대해 생각하고 해결하는 논리적 방법을 찾아야합니다. 어쨌든 내 세부 사항은 자바와 관련된 재미있는 방법이며 생산 과정에서 문제와 해결 경로는 재미있는 작업과 매우 다릅니다! 그러나 키 / 값 동작이 문제가 아니고 데이터 구조를 갖는 것을 발견 할 때 사용할 수 있습니다.
java acm

13

지정된 값을이 맵의 지정된 키와 연관시킵니다. 맵에 이전에 키에 대한 맵핑이 포함 된 경우 이전 값이 대체됩니다.


12

그것은 기존 값 대신 각각의 키에 대한지도를. 같은 이름의 키가 없으면 제공된 값으로 키를 만듭니다. 예 :

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","two");

OUTPUT 키 = "1", 값 = "two"

따라서 이전 값을 덮어 씁니다.


4

지도가 양동이와 같은지 여부에 대한 질문 : 아니오.

name=value쌍이 있는 목록과 name같지만 String 일 필요는 없습니다 (그렇지만 가능합니다).

요소를 얻으려면 키를 get () 메서드에 전달하면 할당 된 객체가 반환됩니다.

그리고 해시 맵은 get-method를 사용하여 객체를 검색하려고하면 실제 객체를 제공된 객체와 비교하지 않습니다. 목록을 반복하고 키를 비교해야하기 때문입니다. 현재 요소를 제공했습니다.

이것은 비효율적입니다. 대신, 객체가 무엇으로 구성되어 있더라도 두 객체 모두에서 소위 해시 코드를 계산하고 비교합니다. int2 개의 전체 (아마도 매우 복잡한) 객체 대신 2를 비교하는 것이 더 쉽습니다 . 해시 코드는 미리 정의 된 길이 (int)를 갖는 요약과 같이 상상할 수 있으므로 고유하지 않으며 충돌이 있습니다. 링크를 삽입 한 설명서에서 해시 코드에 대한 규칙을 찾을 수 있습니다.

이것에 대해 더 알고 싶다면 javapractices.comtechnofundo.com의 기사를 살펴보고 싶을 것이다.

문안 인사


3

나는 항상 사용했다 :

HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();

하나의 식별 키에 여러 가지를 적용하고 싶다면

public void MultiHash(){
    HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();
    String key = "Your key";

    ArrayList<String> yourarraylist = hashy.get(key);

    for(String valuessaved2key : yourarraylist){
        System.out.println(valuessaved2key);
    }

}

당신은 항상 이런 식으로 뭔가를하고 미로를 만들 수 있습니다!

public void LOOK_AT_ALL_THESE_HASHMAPS(){
    HashMap<String, HashMap<String, HashMap<String, HashMap<String, String>>>> theultimatehashmap = new HashMap <String, HashMap<String, HashMap<String, HashMap<String, String>>>>();
    String ballsdeep_into_the_hashmap = theultimatehashmap.get("firststring").get("secondstring").get("thirdstring").get("forthstring");
}

2

JDK의 맵은 중복 키 아래에 데이터를 저장하기위한 것이 아닙니다.

  • 기껏해야 새로운 가치가 이전의 가치보다 우선합니다.

  • 최악의 시나리오 는 예외입니다 (예 : 스트림으로 수집하려고 할 때).

중복 없음 :

Stream.of("one").collect(Collectors.toMap(x -> x, x -> x))

확인. 당신은 얻을 것이다 : $ 2 ==> {one = one}

중복 스트림 :

Stream.of("one", "not one", "surely not one").collect(Collectors.toMap(x -> 1, x -> x))

예외 java.lang.IllegalStateException : 중복 키 1 (하나가 아닌 하나의 값을 병합하려고 시도 함) | Collectors.duplicateKeyException (Collectors.java:133) | Collectors.lambda $ uniqKeysMapAccumulator $ 1 (Collectors.java:180) | ReduceOps $ 3ReducingSink.accept (ReduceOps.java:169) | Spliterators에서 $ ArraySpliterator.forEachRemaining (Spliterators.java:948) | AbstractPipeline.copyInto에서 (AbstractPipeline.java:484) | AbstractPipeline.wrapAndCopyInto (AbstractPipeline.java:474) | ReduceOps $ ReduceOp.evaluateSequential (ReduceOps.java:913)에서 | at AbstractPipeline.evaluate (AbstractPipeline.java:234) | at ReferencePipeline.collect (ReferencePipeline.java:578) | (# 4 : 1)

중복 키를 처리하려면 https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html 과 같은 다른 패키지를 사용 하십시오.

중복 키를 처리하는 다른 많은 구현이 있습니다. 그것들은 웹에 필요합니다 (예 : 중복 된 쿠키 키, Http 헤더는 같은 필드를 가질 수 있습니다 ...)

행운을 빕니다! :)


"재정의"작업 비용이 많이 듭니까?
gaurav

JDK 만 사용하여 해결할 수 있습니다. Collectors.toMap()세 번째 인수-병합 기능이 있습니다. 마지막 중복 요소를 단순히 무시하려면 : Stream.of("one", "two", "one").collect(Collectors.toMap(x -> x, x -> x, (key1, key2) -> key2)). 링크
혼자 서

또한 두 번째 코드 예제가 올바르지 않습니다. 이 입력 : "one", "not one", "surely not one"모든 문자열이 다르기 때문에 중복 키 오류가 발생하지 않습니다.
독립형

안녕 @ 스탠드 홀로. 맵핑 기능 (toMap)을주의해서 읽으십시오.
Witold Kaczurba

안녕하세요 @WitoldKaczurba. 게시하기 전에 코드를 컴파일하십시오.
독립형


1

예, 이는 값이있는 1 개의 모든 키가 마지막으로 추가 된 값으로 덮어 쓰여지고 여기에 "확실히 하나가 아님"을 추가하므로 "하나가 아님"만 표시됩니다.

루프로 표시하려고해도 동일한 키를 가진 하나의 키와 값만 표시합니다.


0
         HashMap<Emp, Emp> empHashMap = new HashMap<Emp, Emp>();

         empHashMap.put(new Emp(1), new Emp(1));
         empHashMap.put(new Emp(1), new Emp(1));
         empHashMap.put(new Emp(1), new Emp());
         empHashMap.put(new Emp(1), new Emp());
         System.out.println(empHashMap.size());
    }
}

class Emp{
    public Emp(){   
    }
    public Emp(int id){
        this.id = id;
    }
    public int id;
    @Override
    public boolean equals(Object obj) {
        return this.id == ((Emp)obj).id;
    }

    @Override
    public int hashCode() {
        return id;
    }
}


OUTPUT : is 1

equals 및 hashCode () 메소드를 올바르게 재정의 한 경우 해시 맵에서 중복을 허용하지 않음을 의미합니다.

HashSet도 내부적으로 HashMap을 사용합니다. 소스 문서를 참조하십시오.

public class HashSet{
public HashSet() {
        map = new HashMap<>();
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.