web-dev-qa-db-ja.com

arraylistのハッシュマップを作成する最良の方法

.txt形式で100万行のデータがあります。形式は非常に単純です。行ごとに:

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

私の言っていることが分かるよね。ユーザーごとに、何度も表示されることもあれば、一度しか表示されないこともあります(決してわかりません)。各ユーザーのすべての値を見つける必要があります。ユーザーはランダムに表示される可能性があるため、Hashmapを使用して実行しました。つまり、HashMap(key:String、value:ArrayList)です。ただし、データをarrayListに追加するには、HashMap get(key)を使用してarrayListを取得し、値を追加してから、HashMapに戻す必要があります。それほど効率的ではないと感じています。誰もがそれを行うためのより良い方法を知っていますか?

28
eric

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]
64
Steve Kuo

Googleコレクションのマルチマップを使用します。同じキーに複数の値を許可します

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

12
Yoni Roit

HashMapのArrayList値は参照です。 「HashMapに戻す」必要はありません。 HashMapの値として既に存在するオブジェクトを操作しています。

4
anthony

ライブラリをインポートしたくない場合。

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;    
    }    
  }    
}    
4
Stuart Clark

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);
2
ilopezluna

あなたが望むのはマルチマップだと思います。 Apacheのcommonsコレクション、またはgoogle-collectionsから取得できます。

http://commons.Apache.org/collections/

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

「マップに似ていますが、複数の値を単一のキーに関連付けることができます。同じキーで異なる値を使用してput(K、V)を2回呼び出すと、マルチマップにはキーから両方の値へのマッピングが含まれます。」

1
kctang

簡単な方法が見つかりませんでした。 MultiMapは常に利用可能なオプションではありません。だから私はこれを書いた。

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;
    }
}
0
Ankur