문제

.txt 형식으로 백만 행의 데이터가 있습니다. 형식은 매우 간단합니다. 각 행에 대해 :

user1,value1
user2,value2
user3,value3
user1,value4
...

당신은 내가 무슨 뜻인지 알고 있습니다. 각 사용자의 경우 여러 번 나타나거나 한 번만 나타날 수 있습니다 (알 수 없습니다). 각 사용자의 모든 값을 찾아야합니다. 사용자가 무작위로 나타날 수 있으므로 해시 맵을 사용하여 수행했습니다. 즉, 해시 맵 (키 : 문자열, 값 : ArrayList). 그러나 Arraylist에 데이터를 추가하려면 Arraylist를 얻으려면 Hashmap get (key)을 지속적으로 사용하여 Arraylist를 가져 와서 값을 추가 한 다음 해시 맵에 다시 넣어야합니다. 그렇게 효율적이지 않다고 생각합니다. 누구든지 그렇게하는 더 좋은 방법을 알고 있습니까?

도움이 되었습니까?

해결책

배열리스트를지도에 다시 다시 구입할 필요가 없습니다. ArrayList가 이미 존재하면 값을 추가하십시오.

개선 된 구현은 다음과 같습니다.

Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();

각 라인을 처리하는 동안 :

String user = user field from line
String value = value field from line

Collection<String> values = map.get(user);
if (values==null) {
    values = new ArrayList<String>();
    map.put(user, values)
}
values.add(value);

후속 2014 년 4 월 - Google Guava에 대한 지식이 제한되어 2009 년에 원래 답변을 썼습니다. Google Guava가하는 모든 일에 비추어 이제는 Multimap 재발 명 대신.

Multimap<String, String> values = HashMultimap.create();
values.put("user1", "value1");
values.put("user2", "value2");
values.put("user3", "value3");
values.put("user1", "value4");

System.out.println(values.get("user1"));
System.out.println(values.get("user2"));
System.out.println(values.get("user3"));

출력 :

[value4, value1]
[value2]
[value3]

다른 팁

Google 컬렉션에서 멀티 맵을 사용하십시오. 동일한 키에 대해 여러 값을 허용합니다

https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/multimap.html

해시 맵의 배열리스트 값은 참조입니다. "해시 맵에 다시 넣을 필요가 없습니다". 해시 맵의 값으로 이미 존재하는 객체에서 작동하고 있습니다.

라이브러리를 가져오고 싶지 않은 경우.

package util;    

import java.util.ArrayList;    
import java.util.HashMap;    
import java.util.List;    

/**    
 * A simple implementation of a MultiMap. This implementation allows duplicate elements in the the    
 * values. (I know classes like this are out there but the ones available to me didn't work).    
 */    
public class MultiMap<K, V> extends HashMap<K, List<V>> {    

  /**    
   * Looks for a list that is mapped to the given key. If there is not one then a new one is created    
   * mapped and has the value added to it.    
   *     
   * @param key    
   * @param value    
   * @return true if the list has already been created, false if a new list is created.    
   */    
  public boolean putOne(K key, V value) {    
    if (this.containsKey(key)) {    
      this.get(key).add(value);    
      return true;    
    } else {    
      List<V> values = new ArrayList<>();    
      values.add(value);    
      this.put(key, values);    
      return false;    
    }    
  }    
}    

부터 Java 8 당신이 사용할 수있는 map.computeIfAbsent

https://docs.oracle.com/javase/8/docs/api/java/util/map.html#computeifabsent-k-java.util.function-function-

Collection<String> values = map.computeIfAbsent(user, k -> new ArrayList<>());
values.add(value);

나는 당신이 원하는 것이 멀티 맵이라고 생각합니다. Apache의 Commons Collection 또는 Google 수집에서 얻을 수 있습니다.

http://commons.apache.org/collections/

http://code.google.com/p/google-collection/

"맵과 비슷하지만 여러 값을 단일 키와 연관시킬 수 있습니다. 풋 (k, v)을 두 번 호출하면 동일한 키이지만 다른 값으로 두 번 호출하면 멀티 맵에는 키에서 두 값으로 매핑이 포함되어 있습니다."

쉬운 방법을 찾을 수 없었습니다. 멀티 맵이 항상 사용할 수있는 옵션은 아닙니다. 그래서 나는 이것을 썼습니다.

public class Context<K, V> extends HashMap<K, V> {

    public V addMulti(K paramK, V paramV) {
        V value = get(paramK);
        if (value == null) {
            List<V> list = new ArrayList<V>();
            list.add(paramV);
            put(paramK, paramV);
        } else if (value instanceof List<?>) {
            ((List<V>)value).add(paramV);
        } else {
            List<V> list = new ArrayList<V>();
            list.add(value);
            list.add(paramV);
            put(paramK, (V) list);
        }
        return paramV;
    }
}

ArrayList가 용량에 가깝게 크기를 조정해야하므로 ArrayList 대신 LinkedList를 사용하면 더 빠릅니다.

또한 반복적 인 재료를 피하기 위해 만들고있는 포장 컬렉션 (해시 맵 또는 멀티 맵)의 용량을 적절하게 추정하고자합니다.

이미 언급했듯이 MultiMap 최선의 선택입니다.

데이터 파일의 비즈니스 요구 사항 또는 제약 조건에 따라 일회성 정렬을 수행하여로드에보다 최적화하도록하는 것을 고려할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top