最も効率的に増分地図の値をJava
-
09-06-2019 - |
質問
この問題になっているものの基本的なこのフォーラムがします。私はどんな風にrefactor一部のコードのためのより良い性能が実行った。
なんて言われちゃを作周波数の単語リスト地図を使って(おそらく、HashMapには、各キーの文字列のあとの数の値が整数であることになるたびに採番され、トークンの言葉のとおりである。
Perlでは、incrementingような価値がtriviallyす:
$map{$word}++;
がJavaでもが複雑化してきております。こちらの道になっていましたが、そ:
int count = map.containsKey(word) ? map.get(word) : 0;
map.put(word, count + 1);
もちろん、自動ボックス化特徴は、新しいJavaできます。んを提案することができ効率的なincrementingな値です。があるのも良いパフォーマンス上の理由のためのeschewingのCollections frameworkを使うょうか?
更新:ね試験の数を答えなのです。下記を参照してください。
解決
一部の試験結果
いいただいた多くの回答--さん--とやりがいを感じていました走行試験によって、図る手法が実際にできます。の方法ではこれらの:
- のContainsKey"する方法について紹介しましたが、本年 の質問
- の"TestForNull方法を提案するAleksandar Dimitrov
- の"AtomicLong"法案によるハンク-ゲイ
- の宝庫"の方法を提案するjrudolph
- の"MutableInt方法を提案するphax.myopenid.com
方法
こちらはなか...
- で構成されるクラスが同一の違いを以下に示します。各クラスのための操作となりますの代表的なシナリオについて紹介しましたが、本:開10MBファイルを読むことで、その周波数カウントのすべての単語トークンはファイルです。このた平均で3秒までの周波数カウント(I/O)10ます。
- timedループでの10回の反復が の入出力操作が前の入出力操作 を記録し、合計時間(クロック秒)基本的に使用 アンダーウィンの手法るドキュメンテーションシステムCookbook.
- 行全試験シリーズに、そしてかったこと。
- 平均の結果法です。
結果
私は現在の結果は以下のコードをされる方に興味がありました。
の ContainsKey 方法でしたが、最も遅いので、したいと思います。速度の各手法の比較に速います。
- ContainsKey: 30.654秒(ベースライン)
- AtomicLong: 29.780秒(1.03倍速)
- TestForNull: 28.804秒(1.06倍速)
- ■インターネット接続無料■: 26.313秒(1.16倍速)
- MutableInt: 25.747秒(1.19倍速)
結論
それだけのMutableInt法や■インターネット接続無料■方法を大幅に高速化、ともに性能を向上させつ以上の10%程度にとどまっています。ただし、スレッドは、AtomicLongれよりも魅力的その他(ゃない).もっとTestForNull final
変数は、その差は無視できます。
こんなに絞りメモリ使用量の異なるシナリオ.嬉しいでからお持ちの方ならどなたでも良いあり方を考えるMutableIntや■インターネット接続無料■方法に影響を及ぼす可能性があるメモリ使用量
個人的を見せていただいたのですが、MutableInt方法の最大の魅力ではな条件が記載されている場合は、第三者ます。な場合を除いて課題を発見し、こんがります。
このコード
こちらは重要なコードから各方法です。
ContainsKey
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
int count = freq.containsKey(word) ? freq.get(word) : 0;
freq.put(word, count + 1);
TestForNull
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
Integer count = freq.get(word);
if (count == null) {
freq.put(word, 1);
}
else {
freq.put(word, count + 1);
}
AtomicLong
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
...
final ConcurrentMap<String, AtomicLong> map =
new ConcurrentHashMap<String, AtomicLong>();
...
map.putIfAbsent(word, new AtomicLong(0));
map.get(word).incrementAndGet();
■インターネット接続無料■
import gnu.trove.TObjectIntHashMap;
...
TObjectIntHashMap<String> freq = new TObjectIntHashMap<String>();
...
freq.adjustOrPutValue(word, 1, 1);
MutableInt
import java.util.HashMap;
import java.util.Map;
...
class MutableInt {
int value = 1; // note that we start at 1 since we're counting
public void increment () { ++value; }
public int get () { return value; }
}
...
Map<String, MutableInt> freq = new HashMap<String, MutableInt>();
...
MutableInt count = freq.get(word);
if (count == null) {
freq.put(word, new MutableInt());
}
else {
count.increment();
}
他のヒント
OKなので、あらかじめご了承とを義務付けられているが短い方がJava8:
Map.merge(key, 1, Integer::sum)
くでおすすめ:の場合 キー ないが、 1 としての価値、そうでない 和1 の値をリンク キー.詳細情報 こちらの
少し研究を2016年 https://github.com/leventov/java-word-count, ベンチマークのソースコード
最高の結果の一手法(小り):
time, ms
kolobokeCompile 18.8
koloboke 19.8
trove 20.8
fastutil 22.7
mutableInt 24.3
atomicInteger 25.3
eclipse 26.9
hashMap 28.0
hppc 33.6
hppcRt 36.5
るスペース結果:
Google グァバ お友---
...以上の場合があります。この素敵 AtomicLongMap.特に良い対応 長 としての価値。
E.g.
AtomicLongMap<String> map = AtomicLongMap.create();
[...]
map.getAndIncrement(word);
も可能追加その1での値:
map.getAndAdd(word, 112L);
@ハンク-ゲイ
上げる資源-アジア-アフリカに自分のななし)のコメント:■インターネット接続無料■のように見える月がかかるものと思われます。場合、理由の如何にかかわらず、また棒の標準、JDK ConcurrentMap や AtomicLong できるのは、コード、 小さな ビット級がYMMV.
final ConcurrentMap<String, AtomicLong> map = new ConcurrentHashMap<String, AtomicLong>();
map.putIfAbsent("foo", new AtomicLong(0));
map.get("foo").incrementAndGet();
休み 1
としての価値をマップ foo
.現実的に増加し、使えるスレッドはすべてこのアプローチをお勧めします。
いつでも良いアイデアの Googleの図書館所蔵 このようなものです。この場合、 Multiset だという:
Multiset bag = Multisets.newHashMultiset();
String word = "foo";
bag.add(word);
bag.add(word);
System.out.println(bag.count(word)); // Prints 2
が図のような方法を繰り返し処理を行キー/エントリなど。内部実装の現在の使用 HashMap<E, AtomicInteger>
, いませんがボクシングコスト
を認識しておく必要があり、このオリジナルの試み
int count = map.containsKey(word) ? map.get(word) : 0;
が潜在的に高価な事業を地図、 containsKey
や get
.の元を行う操作性も似のできることができなくなり、作業 回!
また、APIの地図 get
業務を通常に戻 null
地図を含まない、要求された要素になります。
れますので、ご注意い合わせ頂きますようように
map.put( key, map.get(key) + 1 );
め、危険を伴う利回り NullPointerException
s.ご確認いただくために null
ます。
にも注, ことは非常に重要だが、それ HashMap
s ができ を含む nulls
により定義で設定します。ういうわけではありません返される null
と"などはありませんすることができるこの点、 containsKey
動作 異なる から get
実際のではないことがおわかり頂け るかどうか あな要素になります。を参照してのAPIです。
お場合は、しかししない場合があります。たいと保存されている null
と"noSuchElement".行わない場合は許可す null
sしょう。、 Hashtable
.使用ラッパーとしての図書館で提案したその他の回答がより良い解決策マニュアル処理によっては、複雑さのご使用をご検討ください。
の答え(とり忘れてしまったので入れるので、編集機能!), 最そのネイティブは、 get
入 final
変数のチェック null
や put
いと 1
.変数のべき final
で変更できます。のコンパイラが必要になりのヒントがより明確にすることができてうれしいです。
final HashMap map = generateRandomHashMap(); final Object key = fetchSomeKey(); final Integer i = map.get(key); if (i != null) { map.put(i + 1); } else { // do something }
ない場合はな自動ボックス化すべきと言うようなもの map.put(new Integer(1 + i.getValue()));
です。
Map<String, Integer> map = new HashMap<>();
String key = "a random key";
int count = map.getOrDefault(key, 0);
map.put(key, count + 1);
ことになるす増分値を簡単なコードです。
給付金額:
- な作りのクラス変更可能なint
- 短いコード
- 理解しやすい
- 無nullポインタが例外
別の方法は、合法ですが、これは、やりすぎでincrementingとなります。
map.merge(key, 1, (a,b) -> a+b);
提案:きいコードを読みやすさ以上に少な性能を得た。
別の言い方をするを変更可能な整数:
class MutableInt {
int value = 0;
public void inc () { ++value; }
public int get () { return value; }
}
...
Map<String,MutableInt> map = new HashMap<String,MutableInt> ();
MutableInt value = map.get (key);
if (value == null) {
value = new MutableInt ();
map.put (key, value);
} else {
value.inc ();
}
もちろんこ作りに追加オブジェクトが、オーバーヘッドとの比較を整数値もし整数です。valueOfないます。
手軽に取得することができ computeIfAbsent 方法 Map
提供インタフェースに Java8.
final Map<String,AtomicLong> map = new ConcurrentHashMap<>();
map.computeIfAbsent("A", k->new AtomicLong(0)).incrementAndGet();
map.computeIfAbsent("B", k->new AtomicLong(0)).incrementAndGet();
map.computeIfAbsent("A", k->new AtomicLong(0)).incrementAndGet(); //[A=2, B=1]
の方法 computeIfAbsent
かどうかをチェックします指定されたキーがすでに関連付けられている値ではありませんか?ていない場合に関連付けられた値をその試みを計算する値を、指定されたマッピング機能です。場合を返します現在の既存または計算値は指定されたキーに関連付けられた、またはnullの場合は計算値はnullになります。
に上場してい状態で複数のスレッドを更新共和をご覧いただけます。で LongAdder クラスです。高争、期待されるスループットは、このクラスが大幅に上 AtomicLong
, の高い空間を消費する。
メモリ回転する問題ここで、以来、毎ボクシングのint数128の原因となるオブジェクト配置(整数です。valueOf(int)).は、ガベージコレクタ非常に効率的に扱う短期間稼動のオブジェクト、性能が使用します。
わかればその数を単位として主なものは、+キーの数(=言葉この場合は使用を考慮するintのホルダーです。Phaxれコードす。ここでは、二つの変ホルダークラス製の静的及び初期値の設定1):
static class MutableInt {
int value = 1;
void inc() { ++value; }
int get() { return value; }
}
...
Map<String,MutableInt> map = new HashMap<String,MutableInt>();
MutableInt value = map.get(key);
if (value == null) {
value = new MutableInt();
map.put(key, value);
} else {
value.inc();
}
が必要な場合は極限性能、地図を実施する形で注目を集める"にカスタマイズプリミティブ値です。jrudolphて GNU■インターネット接続無料■.
ちなみに、良い検索のための科目である"ヒストグラム".
の代わりに呼び出しcontainsKey()でより速やかに話す。getおよびチェックの場合、返される値はnullです。
Integer count = map.get(word);
if(count == null){
count = 0;
}
map.put(word, count + 1);
ご確認くださいこのボトルネック?お仕パフォーマンス。
は受け付けていませんXsltproc、プロファイラ(無料入NB6.1)を眺めるホットスポット.
最後に、JVMバージョンアップ(と言うから1.5->1.6)がしばしば安価で性能ブースター.もにアップグレードビルド番号を提供できる良い性能の向上.の場合はWindowsおよびこのサーバクラスの利用-サーバのコマンドラインのサーバーのホットスポットJVM.LinuxおよびSolaris機械こautodetected.
あのアプローチ:
使用バッグalorithmのようなセットに含まれるGoogleョンにします。
を変更可能なコンテナですの地図
class My{
String word;
int count;
}
利用put("図"から、新しいマ("で"));を確認することができ存在する場合には、増加.
を避ける転がり独自のソリューションリストですinnerloopの検索とソート、性能悪臭.最初のHashMapの解いて欠かせない条件でしょうが、しかし正しいからGoogle館があります。
数字を回収するとどうなるのかわかりません
HashMultiset s = new HashMultiset();
s.add("word");
s.add("word");
System.out.println(""+s.count("word") );
のHashMultisetあelegentので、バッグ-アルゴリズムで必要なものが数えます。
と思いソリューションの標準的な方法でどんな自分ではどのように変動するというインターネットには想像もつかな可能です。
お席 GNU■インターネット接続無料■.これは図書館を含むあらゆる高速のプリミティブョンにします。ご使用例 TObjectIntHashMap る方法adjustOrPutValueせいただけたらと思っています。
の変化にMutableIntアプローチがさらに加速してしまう場合、ビットのハックは、モーバイルコンピューティング要素int配列:
Map<String,int[]> map = new HashMap<String,int[]>();
...
int[] value = map.get(key);
if (value == null)
map.put(key, new int[]{1} );
else
++value[0];
れば面白いのですが再ご性能試験はこの変化による。こういったところからできます。
編集:上記のパターンの現代美術館などが私にとって、最終的に変更しま使用■インターネット接続無料■は、アメリカのファッション低減のメモリサイズに非常に大きな地図ったのをとても早くなるのです。
ひとつの素敵な特徴は、 TObjectIntHashMap
クラスは、シングル adjustOrPutValue
通話するかどうかに応じて、すでに値がそのキーにするか、または入初期値または値が既存の値とする。この最適incrementing:
TObjectIntHashMap<String> map = new TObjectIntHashMap<String>();
...
map.adjustOrPutValue(key, 1, 1);
Google集HashMultiset:
-非常に優雅な利用
-その消費のCPUやメモリ
ベストっていた、という方法のように: Entry<K,V> getOrPut(K);
(優雅なり、低コスト)
このような方法は計算のハッシュおよび指数を一度だけ そこをしたいエントリ (交換を更新します。
によりエレガント:
のひとつと位置付け HashSet<Entry>
-しているように get(K)
け新規参入に必要な場合
入できる独自のオブジェクトです。
--> (new MyHashSet()).get(k).increment();
"put"必要の取得"get"を重複していないことを確認しています。
なを直接行う"け",
場合がありました以前の値、または追加しました。
Map map = new HashMap ();
MutableInt newValue = new MutableInt (1); // default = inc
MutableInt oldValue = map.put (key, newValue);
if (oldValue != null) {
newValue.add(oldValue); // old + inc
}
場合はカウントが0から始まし追加1:(又はその他の価値に...)
Map map = new HashMap ();
MutableInt newValue = new MutableInt (0); // default
MutableInt oldValue = map.put (key, newValue);
if (oldValue != null) {
newValue.setValue(oldValue + 1); // old + inc
}
注意: このコードはスレッドで安全です。使いやすさを提供しますその利用の地図は、同時に更新します。
最適化 ループでは、古い値となる新たな価値を次のループを実行します。
Map map = new HashMap ();
final int defaut = 0;
final int inc = 1;
MutableInt oldValue = new MutableInt (default);
while(true) {
MutableInt newValue = oldValue;
oldValue = map.put (key, newValue); // insert or...
if (oldValue != null) {
newValue.setValue(oldValue + inc); // ...update
oldValue.setValue(default); // reuse
} else
oldValue = new MutableInt (default); // renew
}
}
各種のプリミティブの包装を開ける、例えば、 Integer
は不変であり、かなり簡潔ないか聞こうとしているのですが ない限り ができないようなもの AtomicLong.日本語訳を見てもわかりませんが、行け分。余談ですが、 ハッシュテーブル は 一部の Collections Framework.
思使用さ集Lazy地図(初期値0を使っMutableIntegersからApache Langの値としてこの地図です。
最高のコストであることserachの地図を回ご方法です。鉱山だそれだけです。だけの値を取得します(なりますので初期化されない場合は)を増加させます。
の 機能Java 図書館 TreeMap
datastructureは update
法の最新幹線ヘッド:
public TreeMap<K, V> update(final K k, final F<V, V> f)
使用例:
import static fj.data.TreeMap.empty;
import static fj.function.Integers.add;
import static fj.pre.Ord.stringOrd;
import fj.data.TreeMap;
public class TreeMap_Update
{public static void main(String[] a)
{TreeMap<String, Integer> map = empty(stringOrd);
map = map.set("foo", 1);
map = map.update("foo", add.f(1));
System.out.println(map.get("foo").some());}}
このプログラム版画を2です。
@Vilmantas Baranauskas:この答えに、コメントになっていたrepポイントもしっかり身につけるた.と思いますが、カウンタークラス定義がはスレッドセーフではありませんとしてだけでは十分ではありませんでの同期株式会社()な同期値().その他のスレッドを呼び値()を保証するものではありませんのの価値のない限りが起こる前に関係して設立されました。
わからないの効率化だけではありませんが、以下のコードとして働きます。に定義する必要があり、 BiFunction
います。プラスできる以上の増加とのことです。
public static Map<String, Integer> strInt = new HashMap<String, Integer>();
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> bi = (x,y) -> {
if(x == null)
return y;
return x+y;
};
strInt.put("abc", 0);
strInt.merge("abc", 1, bi);
strInt.merge("abc", 1, bi);
strInt.merge("abc", 1, bi);
strInt.merge("abcd", 1, bi);
System.out.println(strInt.get("abc"));
System.out.println(strInt.get("abcd"));
}
出力
3
1
使用している場合は、 Eclipse集, してお使いいただけます HashBag
.ますので、最も効率的なアプローチのメモリ使用量ともに行うもの命令の高速実行を実現します。
HashBag
どちらか MutableObjectIntMap
が格納されているプリミティブ整数ではなく Counter
オブジェクト。このメモリを削減費用の改善命令の高速実行を実現します。
HashBag
提供したいAPIがいが必要か Collection
ることもできるクエリを発行数項目が異なる場合もあります。-
この一例から Eclipse蔵型.
MutableBag<String> bag =
HashBag.newBagWith("one", "two", "two", "three", "three", "three");
Assert.assertEquals(3, bag.occurrencesOf("three"));
bag.add("one");
Assert.assertEquals(2, bag.occurrencesOf("one"));
bag.addOccurrences("one", 4);
Assert.assertEquals(6, bag.occurrencesOf("one"));
注意: 私はコミット者のためのEclipseョンにします。
簡単に、利用の内蔵機能 Map.java
してい
map.put(key, map.getOrDefault(key, 0) + 1);
以来、多くの人の検索Javaの課題はGroovyの答えは、どのように行うことができるので、Groovy:
dev map = new HashMap<String, Integer>()
map.put("key1", 3)
map.merge("key1", 1) {a, b -> a + b}
map.merge("key2", 1) {a, b -> a + b}
待ってからだのしくみを理解する問題を正しく、私をJavaからPythonいに共感できるご苦労を経験することになり
の場合
map.put(key, 1)
いい
map.put(key, map.get(key) + 1)
武器agiは、dexで下がらないboxerぐ!