ここで@NimChimpskyとの議論への応答として、ソートされたコレクションを使用する、代替のより高速な-私が証明しようとしている-カウント方法があります。要素の数と「sortFactor」(コードを参照)によって速度の違いは異なりますが、実行環境(デバッグではない)の大量のオブジェクトの場合、私のメソッドはデフォルトの方法と比較して20〜30%の速度が向上します。以下は、両方のメソッドの簡単なテスト クラスです。
public class EltCountTest {
final static int N_ELTS = 10000;
static final class SampleCountedObject implements Comparable<SampleCountedObject>
{
int value = 0;
public SampleCountedObject(int value) {
super();
this.value = value;
}
@Override
public int compareTo(SampleCountedObject o) {
return (value == o.value)? 0:(value > o.value)?1:-1; // just *a* sort
}
@Override
public int hashCode() {
return value;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SampleCountedObject) {
return value == ((SampleCountedObject)obj).value;
}
return false;
}
@Override
public String toString() {
return "SampleCountedObject("+value+")";
}
}
/**
* * @param args
*/
public static void main(String[] args) {
int tries = 10000;
int sortFactor = 10;
Map<SampleCountedObject, Integer> map1 = null;
Map<SampleCountedObject, Integer> map2 = null;
ArrayList<SampleCountedObject> objList = new ArrayList<EltCountTest.SampleCountedObject>(N_ELTS);
for (int i =0, max=N_ELTS/sortFactor; i<max; i++){
for (int j = 0; j<sortFactor; j++) {
objList.add(new SampleCountedObject(i));
}
}
long timestart = System.nanoTime();
for (int a=0; a< tries; a++) {
map1 = method1(objList);
}
System.out.println();
long timeend1 = System.nanoTime();
System.out.println();
for (int a=0; a< tries; a++) {
map2 = metod2(objList);
}
long timeend2 = System.nanoTime();
System.out.println();
long t1 = timeend1-timestart;
long t2 = timeend2-timeend1;
System.out.println("\n org count method=["+t1+"]\nsorted collection method=["+t2+"]"+
"\ndiff=["+Math.abs(t1-t2)+"] percent=["+(100d*t2/t1)+"]");
for (SampleCountedObject obj: objList) {
int val1 = map1.get(obj);
int val2 = map2.get(obj);
if (val1 != val2) {
throw new RuntimeException("val1 != val2 for obj "+obj);
}
}
System.out.println("veryfy OK");
}
private static Map<SampleCountedObject, Integer> method1(ArrayList<SampleCountedObject> objList) {
Map<SampleCountedObject, Integer> occurenceMap = new HashMap<SampleCountedObject, Integer>();
for(SampleCountedObject obj: objList){
Integer numOccurrence = occurenceMap.get(obj);
if(numOccurrence == null){
occurenceMap.put(obj, 1);
} else {
occurenceMap.put(obj, ++numOccurrence);
}
}
return occurenceMap;
}
private static Map<SampleCountedObject, Integer> metod2(ArrayList<SampleCountedObject> objList) {
Map<SampleCountedObject, Integer> occurenceMap = new HashMap<SampleCountedObject, Integer>();
int count = 0;
Collections.sort(objList);
SampleCountedObject prevObj = objList.get(0);
for(SampleCountedObject obj: objList){
if (!obj.equals(prevObj)) {
occurenceMap.put(prevObj, count);
count = 1;
} else {
count ++;
}
prevObj = obj;
}
occurenceMap.put(prevObj, count);
return occurenceMap;
}
}
結果が同じであることも確認し、テスト結果を印刷した後に行うことに注意してください。
私が興味深いと思ったのは、デバッグ実行で私のメソッドが元のメソッドよりもかなり遅いことです (これも、コレクション内の要素の数に応じて 10-20%)。