2015-07-16 9 views
5

mam HashMap<Integer, Float> z wpisami:klucz HashMap uzyskać z zakresu liczb jako wartości

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 

Niech załóżmy, że chcę klucz do Float 0,465 (co nie jest istniejąca wartość). 0.465 jest między 0.447 i 0.487, więc chciałbym uzyskać klucz 10.

Pierwsza myśl, która przyszła mi do głowy, była możliwa dzięki 15 instrukcjom if/else if lub instrukcjom switch. Moim zdaniem nie byłoby to jednak zbyt eleganckie i praktyczne.

Czy jest jakiś inny sposób na zrobienie tego?

+2

Odwróć mapę i użyj [NavigableMap] (http://docs.oracle.com/javase/7/docs/api/java/util/NavigableMap.html). – khachik

+0

Po prostu mam listę pływaków. Czytanie 15 pływaków byłoby wystarczająco szybkie. –

+0

Widzę, że wartości są "posortowane" względem relacji kluczy. Czy naprawdę potrzebujesz HashMap? Patrząc na ten przykład widzę, że klucze są "indeksami" z 'List' /' Array' + 1, a wartości są wartościami pod tym indeksem. – Xeon

Odpowiedz

4

Mapa nie jest odpowiednia struktura danych. Użyj TreeSet Zamiast:

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

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

Będzie to wykonać bardzo dobrze: TreeSet znajduje punkt wstawiania w O (log n) czas (jak poszukiwania binarnego), a lista jest zwracany tylko widok (nową listę nie jest tworzony), więc cała operacja jest lekka.

Należy również pamiętać, że elementy nie muszą być dodawane w dowolnej kolejności - TreeSet wewnętrznie utrzymuje ich kolejność, dzięki czemu wyszukiwanie jest szybkie.


Oto niektóre kodu testu:

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

wyjściowa:

10 
+0

'headSet (n) .size()' to 'O (n)'. Takie podejście jest przydatne tylko wtedy, gdy liczba elementów nie jest zbyt duża.Tylko sugestia, aby dodać do swojej odpowiedzi :) A przechowywanie spławów w zestawie zadziała tylko wtedy, gdy nie ma duplikatów;) –

+0

Ostatecznie najprostsze i najskuteczniejsze i czyste rozwiązanie. Zajęło mi około 2 minuty, aby dostosować go do mojego kodu. – zearthur99

+0

@Federico 'headSet(). Size()' to O (1). Zwraca rozmiar podkładu 'NavigableMap', który jest int pola TreeMap. Stworzenie listy podrzędnej może być jednak rozkazem ... jeśli będę miał czas, będę kopać głębiej. – Bohemian

1

Zakładając data jest początkowy mapa i wartości są unikalne, można zrobić:

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

Działa to tak długo, jak nie ma duplikatów. –

1

Jeżeli wartości są zawsze klasyfikowane, wystarczy użyć wspólnej tablicy:

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

a potem, zadzwoń na metę Arrays.binarySearch() d, który zwraca indeks wartości, która jest natychmiast większa od podanej wartości.

Należy pamiętać, że to podejście obsługuje duplikaty wartości, a zwracany indeks to 0-based.

Powiązane problemy