2009-08-21 13 views
30

Mam przypadku użycia, gdzie jeśli liczba wynosi między 0-10 powinien powrócić 0 i jeśli leży ona między 11-20 powinien powrócić 1 itpKorzystanie mapa java dla zakresu wyszukiwania

0 => 0-3, (0 and 3 are inclusive) 
1 => 4-15, (4 and 15 are inclusive) 
2 => 16-40, (16 and 40 are inclusive) 
3 => 41-88, (41 and 88 are inclusive) 
5 => 89-300 (89 and 300 are inclusive) 

Myślałam w jaki sposób mogę wdrożyć i myślał mapy Javie, ale nie pozwala zakres poszukiwania

Jestem zainteresowany czymś takim, mam funkcję

int foo() { 

} 

jeśli foo zwraca 5, ponieważ leży ona między 0 t Ø 10 użyłbym 0, jeśli foo zwrot 25 byłoby użyć 2.

pomysłów

EDIT: Faktycznie zakresy nie są tak proste, jak 0-10, 11-20. Chcę móc wyszukiwać zakresy. Przepraszam za zamieszanie. Na podstawie zapytań dodałem poprawny przykład, liczby są ciągłe:

+0

Proszę podać prawdziwy przykład tego, co chcesz zrobić. –

+1

Zakresy podane w przykładzie nie są ciągłe. Jeśli szuka się 4 lub 50, czy chcesz uzyskać wynik "null", zakres powyżej, poniżej lub najbliższego, lub co? – erickson

+4

@mkal: sposób w jaki zmieniasz wymagania, możesz być menadżerem z piekła rodem :-) –

Odpowiedz

62

Mogę wymyślić kilka możliwych rozwiązań dla bardziej ogólnego problemu, gdy zakresy nie są jednolite i istnieją "dziury". Najprostsze to:

  1. Po prostu zapełnij mapę dla wszystkich ważnych wartości kluczy, z wieloma mapami odwzorowanymi na tę samą wartość. Zakładając, że korzystasz z HashMaps, powinno to być najbardziej wydajne czasowo (O (1)), ale masz więcej pracy w czasie instalacji i używasz więcej miejsca.
  2. Użyj mapy NavigableMap i użyj floorEntry(key), aby wykonać wyszukiwania. To powinno być mniej czasu wydajne (O (log (n) wyszukiwań), ale więcej miejsca skuteczny.

Oto rozwiązanie przy użyciu NavigableMaps, która pozwala na „dziury” w mapowaniu.

private static class Range { 
    public int upper, value; 
    ... 
} 

NavigableMap<Integer, Range> map = new TreeMap<Integer, Range>(); 
map.put(0, new Range(3, 0));  // 0..3  => 0 
map.put(5, new Range(10, 1));  // 5..10 => 1 
map.put(100, new Range(200, 2)); // 100..200 => 2 

// To do a lookup for some value in 'key' 
Map.Entry<Integer,Range> entry = map.floorEntry(key); 
if (entry == null) { 
    // too small 
} else if (key <= entry.getValue().upper) { 
    return entry.getValue().value; 
} else { 
    // too large or in a hole 
} 

Na Natomiast jeżeli nie ma 'dziur' rozwiązanie jest prostsze:

NavigableMap<Integer, Integer> map = new TreeMap<Integer, Integer>(); 
map.put(0, 0); // 0..4  => 0 
map.put(5, 1); // 5..10 => 1 
map.put(11, 2); // 11..200 => 2 

// To do a lookup for some value in 'key' 
if (key < 0 || key > 200) { 
    // out of range 
} else { 
    return map.floorEntry(key).getValue(); 
} 
+1

Jest to bardzo dobre wykorzystanie istniejącej mapy do MapMap zrób proste wyszukiwanie zakresu. Zauważ, że jeśli zachodzą na siebie interwały, to podejście zwróci ten interwał z najbliższym dolnym klawiszem do klucza wyszukiwania. Podobnie, to podejście nie obsługuje wyszukiwania wszystkich nakładających się interwałów zawierających dany klucz wyszukiwania, jak omówiono w http://stackoverflow.com/questions/1580185/data-structure-for-quick-time-interval-look-up – stackoverflowuser2010

+0

Jeśli występują nakładające się zakresy, wówczas (najprawdopodobniej) zakresy są niepoprawnie określone. Przynajmniej to jest moje czytanie TEGO pytania. –

0

Myślę, że to, czego chcesz, to coś podobnego do linii foo()/10, ale da ci to nieco w stosunku do tego, o co prosiłeś. Zawsze możesz po prostu robić porównania z dwoma punktami końcowymi dla każdego elementu w twojej "mapie", jeśli nie podążają za łatwym wzorem.

3

W bardziej ogólnym przypadku, który nie może być rozwiązany z arytmetyczną, możesz utworzyć TreeMap z odpowiednim Komparatorem. Dodaj odwzorowania dla wartości brzegowych, a następnie użyj sufituEntry lub floorEntry, aby znaleźć odpowiednie dopasowanie.

10

Pseudo-kod:

  1. Przechowuj granice zakresu w płaskiej tablicy: new int[] {0, 3, 5, 15, 100, 300}.
  2. Binarne przeszukiwanie tablicy, jak przy wstawianiu liczby do tablicy. Zobacz Arrays.binarySearch().
  3. Jeśli punkt wstawienia jest równy, liczba nie mieści się w żadnym zakresie.
  4. Jeśli punkt wstawiania jest nieparzysty, pasuje do odpowiedniego zakresu. Na przykład punkt wstawienia 10 w powyższej tablicy będzie 3, umieszczając go między 5 i 15, więc należy do drugiego zakresu.
+1

Uwaga: działa to tylko wtedy, gdy mapujemy na liczby całkowite "{0, 1, 2, ...}". W bardziej ogólnych przypadkach należy użyć mapy. –

0

Myślę, że najprostszym rozwiązaniem byłoby dodanie mapowania z górnych granic swoich zakresów do wartości tego przedziału mapy do, i po prostu zwiększając swój numer (klucz w mapie) aż do mapowania (które jest górną granicą zakresu, w którym znajduje się twój numer).

Innym sposobem jest wypełnienie mapy wszystkimi wpisami w zakresie i dodanie mapowania dla każdego z nich.

Który z nich jest bardziej wydajny, zależy od tego, czy jest prawdopodobne, trzeba zwrócić wszystkie numery w zakresie wielokrotnie (użyj tego ostatniego rozwiązania), albo tylko niektóre z numerów kilka razy (użyj najpierw)

Powiązane problemy