Разделите числа в другом диапазоне

Я пытаюсь измерить, сколько времени каждый поток занимает вставку в базу данных. Я записал все эти показатели производительности в карту с именем ConcurrentHashMap, например, сколько времени каждый поток тратит на вставку. В этой параллельной хеш-карте это будет примерно так.

Key- 10
Value- 2

Это означает, что 2 вызова вернулись за 10 мс. Другой пример ниже

Key - 20
Value -1

что означает, что 1 вызов вернулся через 20 мс.

И эта карта будет содержать гораздо больше данных, что означает гораздо больше пар ключ-значение.

Итак, теперь я пытаюсь сделать что-то вроде приведенного ниже, используя ту же карту, что и выше, это означает, что мне нужно повторить приведенную выше карту, чтобы получить приведенные ниже числа в этом конкретном диапазоне. Это возможно сделать?

How many calls(X number) came back in between 1 and 20 ms
How many calls(X number) came back in between 20 and 40 ms
How many calls(X number) came back in between 40 and 60 ms
How many calls(X number) came back in between 60 and 80 ms
How many calls(X number) came back in between 80 and 100 ms
How many calls(X number) came back after 100 ms

Какой-то код, о котором я думал изначально.

SortedSet<Long> keys = new TreeSet<Long>(map.keySet());
for (Long key : keys) {
    System.out.print(key + " : ");
    for (int i = 0; i < map.get(key); i++) {
                 // Not sure what I am supposed to do here?
    }
    System.out.println();
}

Может ли кто-нибудь помочь мне здесь?

Обновление:-

Моя примерная стоимость карты-

{31=3, 48=1, 33=1, 30=12, 43=1, 38=1, 32=1}

Это означает, что общий вызов составил 3+1+1+12+1+1+1 = 20, если добавить value из map.

И из этого мне нужно выяснить, что приведенный выше сценарий означает что-то вроде этого

How many calls(X number) came back in between 1 and 20 ms
How many calls(X number) came back in between 20 and 40 ms
How many calls(X number) came back in between 40 and 60 ms
How many calls(X number) came back in between 60 and 80 ms
How many calls(X number) came back in between 80 and 100 ms
How many calls(X number) came back after 100 ms

Ниже приведен мой код, который я пробовал с приведенным ниже предложением:

private static void drawHistogram (карта карты) {

int counter[] = new int[6];

for (Integer key : map.keySet()) {
    System.out.println("" + key);    

    // add sample
    int idx = key / 20;
    idx = Math.min(idx, counter.length - 1);
    counter[idx]++;
    }

for (int i = 0; i < counter.length; i++) {
    System.out.println(counter[i] + " came back in between " + i * 20 + " and " + (i + 1) * 20
            + " ms");
}

}

Как вы можете видеть, у меня было сделано 20 звонков, но это показывает только 7 звонков. Что-то не так я сделал? Это результат, который я получил-

0 came back in between 0 and 20 ms
5 came back in between 20 and 40 ms
2 came back in between 40 and 60 ms
0 came back in between 60 and 80 ms
0 came back in between 80 and 100 ms
0 came back in between 100 and 120 ms

который показывает только 7 вызовов. Но есть 20 звонков.


person Community    schedule 08.02.2013    source источник
comment
Не голосуйте, чтобы закрыть это - OP разумно спрашивает, какую структуру данных использовать для конкретной, понятной проблемы.   -  person Andrew Alcock    schedule 08.02.2013
comment
Вы пытаетесь распечатать гистограмму?   -  person Apurv    schedule 08.02.2013
comment
просто измените concurrenthashmap на concurrentskiplistmap, который является навигационной картой и предлагает богатый API для выполнения запросов на основе диапазона; мой ответ имеет пример.   -  person Scorpion    schedule 08.02.2013


Ответы (5)


Предвидя необходимость легкого переопределения размера корзины (и, конечно, количества корзин, в которые вы агрегируете), я предлагаю:

    Map<Integer, Integer> values = new HashMap<Integer, Integer>();

    int[] definition = {0, 20, 40, 60, 80, 100};
    int[] buckets = new int[definition.length];

    for (int time : values.keySet()) {
        for (int i=definition.length-1; i>=0; i--) {
            if (time >= definition[i]) {
                buckets[i] += values.get(time);
                break;
            }
        }
    }
    for (int i=0; i<definition.length; i++) {
        String period = "";
        if (i == definition.length-1) {
            period = "greater than " + definition[i] + "ms";
        } else {
            period = "between " +
                      (definition[i]+1) +
                      " and " +
                      definition[i+1] + "ms";
        }
        System.out.println(buckets[i] + " came back " + period);
    }

Конфигурируемость управляется изменением definition. Я использовал следующий код, чтобы проверить это:

    Random rnd = new Random();
    for (int i=0; i<1000; i++) {
        int time = rnd.nextInt(121);
        Integer calls = values.get(time);
        if (calls == null) {
            calls = Integer.valueOf(0);
        }
        calls += 1;
        values.put(time, calls);
    }
person Andrew Alcock    schedule 08.02.2013
comment
Спасибо Андрей за помощь. Определенно ваш код имеет возможность настройки. Единственная трудность, с которой я сталкиваюсь, это то, что вы генерируете случайное число. В моем случае у меня уже есть эти числа в хеш-карте. Я обновил вопрос более подробно. Я пытаюсь изменить ваше предложение для работы с картой, но мне трудно понять. - person ; 08.02.2013
comment
Фу! Извините, я неправильно понял ваш вопрос - я обновлю, чтобы он работал правильно. Дай мне пару минут :) - person Andrew Alcock; 08.02.2013
comment
@FarhanJamal: хорошо, исправлено. Извините за мое замешательство. - person Andrew Alcock; 08.02.2013
comment
Спасибо Андрей за помощь. Работает как шарм. - person ; 08.02.2013

SortedSet<Long> keys = new TreeSet<Long>(map.keySet());
Map<Long, Long> values = new HashMap<Long, Long>();
Integer total = null;
Integer current = null;
Long point = null;
for (Long key : keys) {
    System.out.print(key + " : ");
    current = map.get(key);
    if(key >= 1 && key <= 20) {
        point = 1;
    } // Do Other Comparisons also and change point 2, 3, 4, 5, 6

    total = values.get(point);
    if(total == null) {
        total = 0;
    }
    total += current;
    values.put(point, total);
    System.out.println();
}

Теперь, если вы зациклите keySet из values

Точка 1 будет How many calls(X number) came back in between 1 and 20 ms

person shazin    schedule 08.02.2013

Вы можете попробовать:

SortedSet<Long> keys = new TreeSet<Long>(map.keySet());

int group1To20=0;
int group20To40=0;
int group40To60=0;
int group60To80=0;
int group80To100=0;
int groupAbove100=0;
for (Long key : keys) {
 if(key>=0 && key<=20){
  group1To20=group1To20+map.get(key);
  }elseif(key>20 && key<=40){
   group20To40=group20To40+map.get(key);
  }
 //Similarly do as above for other range of group

}//end of loop


System.out.print("group 1-20 contains " +  group1To20);
//Now print the group range and values here

}

Я пробовал ваше решение. Я могу неправильно понять ваш вопрос. Если да, то проясните для меня вопрос.

person Milan    schedule 08.02.2013

Вы можете использовать NavigableMap, который позволяет запрашивать диапазон чисел (голова, хвост). Поточно-безопасной реализацией является ConcurrentSkipListMap.

В частности, обратите внимание на методы NavigableMap<K,V> headMap(K toKey, boolean inclusive), NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) и SortedMap<K,V> subMap(K fromKey, K toKey)

Пример

//your existing concurrent map changed to concurrent navigable map
NavigableMap<Long, Long> throughputCounter = new ConcurrentSkipListMap<Long, Long>();
            // this prints for inclusive values - 1 and 20 are both included
            System.out.println("How many calls(X number) came back in between 1 and 20 ms:" + calcThroughput(throughputCounter.subMap(1L, true, 20L, true)));
            System.out.println("How many calls(X number) came back in between 20 and 40 ms:" + calcThroughput(throughputCounter.subMap(20L, true, 40L, true)));
            System.out.println("How many calls(X number) came back in between 40 and 60 ms:" + calcThroughput(throughputCounter.subMap(40L, true, 60L, true)));
            System.out.println("How many calls(X number) came back in between 60 and 80 ms:" + calcThroughput(throughputCounter.subMap(60L, true, 80L, true)));
            System.out.println("How many calls(X number) came back in between 80 and 100 ms:" + calcThroughput(throughputCounter.subMap(80L, true, 100L, true)));
            System.out.println("How many calls(X number) came back in after 100 ms:" + calcThroughput(throughputCounter.tailMap(100L)));

    private Long calcThroughput(NavigableMap<Long, Long> subMap) {
        Long sumOfARange = new Long(0);
        for (Long value : subMap.values()) {
            sumOfARange += value;
        }
        return sumOfARange;
    }
person Scorpion    schedule 08.02.2013
comment
Спасибо, Скорпион, за предложение. Я раньше не работал с NavigableMap. Как я буду вызывать здесь метод calcThroughput? Тут немного запутался. - person ; 08.02.2013

Карта вообще не нужна. Вы можете просто разделить время на 20 (мс) и увеличить счетчик в массиве.

public static void main( String[] args) {
    int counter[] = new int[6];
    for ( int i = 0 ; i < 100 ; i++ ) {
        int time = (int) ( Math.random() * 200 );
        System.out.println( "" + time  );
        // add sample
        int idx = time / 20;
        idx = Math.min( idx, counter.length-1);
        counter[idx]++;
    }

    for ( int i = 0 ; i < counter.length ; i++ ) {
        System.out.println( counter[i] + " came back in between " + i*20 + " and " + (i+1)*20 + " ms" );
    }
}

Обратите внимание, что последний элемент массива содержит количество всех выборок >= 100 мс, поэтому вывод должен быть скорректирован. Опущено, чтобы сделать код максимально коротким и понятным.

Пример вывода

13 came back in between 0 and 20 ms
10 came back in between 20 and 40 ms
13 came back in between 40 and 60 ms
10 came back in between 60 and 80 ms
11 came back in between 80 and 100 ms
43 came back in between 100 and 120 ms

ОБНОВЛЕНИЕ: вывод в том виде, в котором он должен быть

for ( int i = 0 ; i < counter.length-1 ; i++ ) {
    System.out.println( counter[i] + " came back in between " + i*20 + " and " + (i+1)*20 + " ms" );
}
System.out.println( counter[counter.length-1] + " came back after 100" ms" );
person stacker    schedule 08.02.2013
comment
Спасибо штабелер за предложение. Я использую Map для хранения этих чисел в методе запуска многопоточного кода. Вот почему на сцену вышла Карта. И тогда я буду использовать эту Карту, чтобы сделать то, что вы предложили мне. - person ; 08.02.2013
comment
@FarhanJamal Вы также можете синхронизировать доступ к массиву: -synchronized ( counter ) { counter[idx]++; } - person stacker; 08.02.2013
comment
Да. Я согласен. Я попробовал ваше предложение, и оно выглядит более чистым. Единственное, чего я не вижу, это то, что в последней строке вашего вывода вы показываете 43 came back in between 100 and 120 ms. Вместо этого есть ли способ показать X came back in greater than 100 ms? Потому что там будут тысячи номеров. Вот почему я пытался упростить его до 100. - person ; 08.02.2013
comment
@FarhanJamal Да, вам нужно только зациклиться с индекса 0..5, чтобы напечатать «между строками» и напечатать 6-й элемент с другим текстом («больше чем»). - person stacker; 08.02.2013
comment
Я думаю, что я испортил свой код, так как использую Map в своем коде. Значит что-то пошло не так. Я обновил вопрос своим примером кода. - person ; 08.02.2013