2015-07-16 3 views
5

У меня есть HashMap<Integer, Float> с записями:ключа в HashMap Получить с диапазоном чисел в качестве значения

1 -> 0.127 
2 -> 0.167 
3 -> 0.207 
4 -> 0.247 
5 -> 0.237 
6 -> 0.327 
7 -> 0.367 
8 -> 0.407 
9 -> 0.447 
10 -> 0.487 
11 -> 0.527 
12 -> 0.567 
13 -> 0.607 
14 -> 0.647 
15 -> 0.652 

Пусть Предположу, что я хочу ключ к Float 0,465 (который не является текущим значением). 0.465 находится между 0.447 и 0.487, поэтому я хотел бы получить ключ 10.

Первая мысль, которая пришла мне в голову, была достигнута с помощью инструкций 15 if/else if или с оператором switch. Но, на мой взгляд, это было бы не очень элегантно и практично.

Есть ли другой способ сделать это?

+2

Отмените свою карту и используйте [NavigableMap] (http://docs.oracle.com/javase/7/docs/api/java/util/NavigableMap.html). – khachik

+0

У меня просто есть список поплавков. Чтение 15 поплавков было бы достаточно быстрым. –

+0

Я вижу, что значения «сортируются» по отношению к ключам. Вам действительно нужен HashMap? Глядя на этот пример, я вижу, что ключи являются «индексами» '' List'/'Array' + 1, а значениями являются значения под этим индексом. – Xeon

ответ

4

карта не соответствующая структура данных. Используйте TreeSet вместо:

TreeSet<Float> numbers = new TreeSet<>(); 
// populate the set with your numbers, in any order, then 

int index = numbers.headSet(n).size() + 1; 

Это будет выполнять очень хорошо: TreeSet находит точку вставки в O (журнал N) времени (например, бинарный поиск) и список возвращаемых только вид (новый список не создается), поэтому вся операция легка.

Также обратите внимание, что элементы не нужно добавлять в каком-либо конкретном порядке - TreeSet внутренне поддерживает свой порядок, поэтому поиск выполняется быстро.


Вот некоторые тестовый код:

TreeSet<Float> numbers = new TreeSet<>(Arrays.asList(
    0.607F, 0.647F, 0.127F, 0.167F, 0.207F, 0.247F, 0.237F, 0.327F, 
    0.367F, 0.407F, 0.447F, 0.487F, 0.527F, 0.567F, 0.652F)); 

Выход:

10 
+0

'headSet (n) .size()' is 'O (n)'. Этот подход полезен только в том случае, если количество элементов не слишком велико.Просто предложение добавить к вашему ответу :) И сохранение поплавков в наборе будет работать только в том случае, если нет дубликатов;) –

+0

Определенно самое простое и эффективное и чистое решение. Мне потребовалось около 2 минут, чтобы адаптировать его к моему коду. – zearthur99

+0

@Federico 'headSet(). Size()' is O (1). Он возвращает размер основы «NavigableMap», который является полем int TreeMap. Создание суб-списка может быть порядком n, хотя ... если у меня будет время, я буду копать глубже. – Bohemian

1

Предполагая data ваша начальная карта и ценности уникальны, вы могли бы сделать:

java.util.NavigableMap<Double, Integer> reverseMap = new java.util.TreeMap<>(); 
for(java.util.Map.Entry<Double, Integer> entry : data.entrySet()) { 
    reverseMap.put(entry.getValue(), entry.getKey()); 
} 
System.out.println(reverseMap.ceilingEntry(0.465).getValue()); 
+0

Это работает, пока нет дубликатов. –

1

Если значения всегда отсортирован, просто использовать общий массив:

double[] values = {0.127, ..., 0.652}; 

А потом, назовите метод Arrays.binarySearch() d, который возвращает индекс значения, которое сразу больше заданного значения.

Обратите внимание, что этот подход поддерживает повторяющиеся значения, а возвращаемый индекс - 0-based.

Смежные вопросы