Java Hashmap: Jak zdobyć klucz z wartości?

450

Jeśli mam wartość "foo"i HashMap<String> ftwdla której ftw.containsValue("foo")zwraca true, w jaki sposób mogę uzyskać odpowiedni klucz? Czy muszę przeglądać skrót mapy? Jak najlepiej to zrobić?

Nick Heiner
źródło
72
Zauważ, że nie ma jednego odpowiedniego klucza - może istnieć wiele mapowań kluczy na tę samą wartość.
CPerkins
1
@CPerkins, ale w przypadku map skrótów, takich jak <strFilename, Reader> i wielu innych 1 do 1, jest to bardzo przydatne.
Wodnik Moc
jeśli masz małą kolekcję przedmiotów, rozważ utworzenie stałej public static final String TIME = "time";iproperties.put(TIME, PbActivityJpa_.time);
Basheer AL-MOMANI
prawdopodobnie może to pomóc w uzyskaniu danych z mapy i możesz również wykonać jakieś przetwarzanie. frugalisminds.com/java/java-8-stream-map-examples
Sanjay-Dev

Odpowiedzi:

215

Jeśli zdecydujesz się użyć biblioteki Commons Kolekcje zamiast standardowego interfejsu API Java Collections, możesz to zrobić z łatwością.

BidiMap interfejs w bibliotece Collections jest dwukierunkowy map, co pozwala odwzorować klucz do wartości (jak normalnych mapach), a także do mapowania wartości do klucza, co pozwala na wykonywanie wyszukiwań w obu kierunkach. Uzyskanie klucza dla wartości jest obsługiwane przez metodę getKey () .

Jest jednak pewne zastrzeżenie, że mapy bidi nie mogą mieć wielu wartości mapowanych na klucze, a zatem dopóki twój zestaw danych nie ma mapowań 1: 1 między kluczami a wartościami, nie możesz używać bidimaps.

Aktualizacja

Jeśli chcesz polegać na interfejsie API kolekcji Java, musisz zapewnić relację 1: 1 między kluczami i wartościami podczas wstawiania wartości do mapy. Łatwiej to powiedzieć niż zrobić.

Gdy możesz to zapewnić, użyj metody entrySet (), aby uzyskać zestaw wpisów (mapowań) na mapie. Po uzyskaniu zestawu, którego typem jest Map.Entry , iteruj wpisy, porównując przechowywaną wartość z oczekiwaną i uzyskaj odpowiedni klucz .

Aktualizacja nr 2

Wsparcie dla map bidi z lekami generycznymi można znaleźć w Google Guava i refactored bibliotekach Commons-Collections (ta ostatnia nie jest projektem Apache). Dziękujemy Esko za zwrócenie uwagi na brakujące ogólne wsparcie w kolekcjach Apache Commons. Używanie kolekcji z rodzajami sprawia, że ​​kod jest łatwiejszy w utrzymaniu.

Vineet Reynolds
źródło
23
... a jeśli lubisz Generics i wszystkie te nowoczesne rzeczy, Google Maps ma BiMap, w którym możesz uzyskać klucz pasujący do określonej wartości, wywołując biMap.inverse (). get (wartość);
Esko
1
Tak, kolekcje Apache Commons nie obsługują generycznych. Istnieją jednak Kolekcje Google, jak już wspomniałeś (których jeszcze nie używam - nie ma jeszcze wersji 1.0), i istnieją ponownie utworzone Kolekcje Commons z obsługą Generics. Znajdziesz to jako projekt Sourceforge @ sourceforge.net/projects/collections
Vineet Reynolds
2
Kolekcje Google nie są refaktoryzowaną wersją zbiorów Commons.
whiskeysierra
12
@whiskeysierra: Nie sądzę, żeby ktokolwiek (obecnie) tak powiedział.
huff
2
Kolekcje Apache obsługują teraz generics commons.apache.org/proper/commons-collections/javadocs/…
kervin
603

Jeśli struktura danych ma mapowanie wiele do jednego między kluczami i wartościami, należy iterować wpisy i wybierać wszystkie odpowiednie klucze:

public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
    Set<T> keys = new HashSet<T>();
    for (Entry<T, E> entry : map.entrySet()) {
        if (Objects.equals(value, entry.getValue())) {
            keys.add(entry.getKey());
        }
    }
    return keys;
}

W przypadku relacji jeden do jednego możesz zwrócić pierwszy dopasowany klucz:

public static <T, E> T getKeyByValue(Map<T, E> map, E value) {
    for (Entry<T, E> entry : map.entrySet()) {
        if (Objects.equals(value, entry.getValue())) {
            return entry.getKey();
        }
    }
    return null;
}

W Javie 8:

public static <T, E> Set<T> getKeysByValue(Map<T, E> map, E value) {
    return map.entrySet()
              .stream()
              .filter(entry -> Objects.equals(entry.getValue(), value))
              .map(Map.Entry::getKey)
              .collect(Collectors.toSet());
}

Ponadto, dla użytkowników Guava, BiMap może być przydatny. Na przykład:

BiMap<Token, Character> tokenToChar = 
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);
Vitalii Fedorenko
źródło
3
Czy możesz powiedzieć coś o spektaklu? Co będzie bardziej zoptymalizowane? To czy BidiMap?
tasomaniac
Myślałem o tym samym rozwiązaniu, oczywiście go poparłem, ale wątpię w jego skuteczność, jeśli chodzi o naprawdę duże Kolekcje.
arjacsoh
3
stackoverflow.com/questions/4553624/hashmap-get-put-complexity HashMap ma złożoność czasową o(1). Jeśli iterujesz po wartościach, zabije to wydajność. Jeśli chcesz better performancei ma one-onezwiązek, możesz użyć another mapgdzievalue is a key
veer7
3
Polecam wymienić .filter(entry -> entry.getValue().equals(value))ze jak nie oświadczenie o zdolności powstał. Ponadto, można wymienić z.filter(entry ->Objects.equals(entry.getValue(), value))null.map(entry -> entry.getKey()).map(Map.Entry::getKey)
Holger
mam problem ze zrozumieniem notacji <T, E> przed Set <T> getKeysByValue () ... jaki jest sens .... inny sposób na zrobienie tego bez korzystania z tego? dzięki
ponderingdev,
76
public class NewClass1 {

    public static void main(String[] args) {
       Map<Integer, String> testMap = new HashMap<Integer, String>();
        testMap.put(10, "a");
        testMap.put(20, "b");
        testMap.put(30, "c");
        testMap.put(40, "d");
        for (Entry<Integer, String> entry : testMap.entrySet()) {
            if (entry.getValue().equals("c")) {
                System.out.println(entry.getKey());
            }
        }
    }
}

Niektóre dodatkowe informacje ... mogą być dla Ciebie przydatne

Powyższa metoda może nie być dobra, jeśli twoja mapa skrótów jest naprawdę duża. Jeśli twoja mapa skrótów zawiera unikatowy klucz do unikalnego mapowania wartości, możesz zachować jeszcze jeden skrót, który zawiera mapowanie od wartości do klucza.

Oznacza to, że musisz zachować dwie mapy skrótów

1. Key to value

2. Value to key 

W takim przypadku możesz użyć drugiej wartości skrótu, aby uzyskać klucz.

Fathah Rehman P.
źródło
19

Myślę, że twoje wybory są

  • Użyj wbudowanej do tego implementacji mapy, takiej jak BiMap z kolekcji Google. Pamiętaj, że kolekcje Google BiMap wymagają unikalnych wartości, a także kluczy, ale zapewnia wysoką wydajność w obu kierunkach
  • Ręcznie utrzymuj dwie mapy - jedną dla klucza -> wartość, a drugą mapę dla wartości -> klucz
  • Iteruj przez entrySet()i, aby znaleźć klucze, które pasują do wartości. Jest to najwolniejsza metoda, ponieważ wymaga iteracji przez całą kolekcję, podczas gdy pozostałe dwie metody tego nie wymagają.
Chi
źródło
19

Możesz wstawić zarówno klucz, parę wartości, jak i jej odwrotność do struktury mapy

map.put("theKey", "theValue");
map.put("theValue", "theKey");

Użycie map.get („theValue”) zwróci następnie „theKey”.

To szybki i brudny sposób, w jaki tworzyłem stałe mapy, które będą działać tylko dla wybranych kilku zestawów danych:

  • Zawiera tylko 1 do 1 par
  • Zbiór wartości jest rozłączny od zestawu kluczy (1-> 2, 2-> 3 je łamie)
Chicowitz
źródło
4
To naprawdę nie jest poprawne. Wymaga to nie tylko 1-1, ale także, że zestaw wartości jest rozłączny od zestawu kluczy. Nie można zastosować tego do mapy dwusuwowej {1 -> 2, 2 -> 3}: 2 jest zarówno wartością, jak i kluczem.
Luis A. Florit,
15

Udekoruj mapę własną implementacją

class MyMap<K,V> extends HashMap<K, V>{

    Map<V,K> reverseMap = new HashMap<V,K>();

    @Override
    public V put(K key, V value) {
        // TODO Auto-generated method stub
        reverseMap.put(value, key);
        return super.put(key, value);
    }

    public K getKey(V value){
        return reverseMap.get(value);
    }
}
ABHI
źródło
Myślę, że jest to interesujące podejście, ale ponieważ relacja musi wynosić 1: 1, pozbyłbym się całkowicie HashMap i zaimplementowałem interfejs Map <K, V>, aby uniknąć duplikatów zarówno wartości, jak i kluczy.
Fran Marzoa,
11

Nie ma jednoznacznej odpowiedzi, ponieważ wiele kluczy można odwzorować na tę samą wartość. Jeśli wymuszasz unikalność za pomocą własnego kodu, najlepszym rozwiązaniem jest utworzenie klasy, która używa dwóch map Hashmap do śledzenia mapowań w obu kierunkach.

rekurencyjny
źródło
11

Aby znaleźć wszystkie klucze, które odwzorowują tę wartość, iteruj wszystkie pary w haszapie, używając map.entrySet().

wsorenson
źródło
4
To rozwiązanie jest strasznie intensywne, do tego stopnia, że ​​jest niepraktyczne w przypadku dużych HashMap.
Joehot200,
10

Za pomocą Java 8:

ftw.forEach((key, value) -> {
    if (value.equals("foo")) {
        System.out.print(key);
    }
});
phani
źródło
6
value=="foo" to nie zadziała. equalsnależy używać do porównywania ciągów.
Anton Balaniuc,
@Anton, prawda, chyba valueże została internowana.
frododot
9

Jeśli budujesz mapę we własnym kodzie, spróbuj połączyć klucz i wartość na mapie razem:

public class KeyValue {
    public Object key;
    public Object value;
    public KeyValue(Object key, Object value) { ... }
}

map.put(key, new KeyValue(key, value));

Następnie, gdy masz wartość, masz również klucz.

David Tinker
źródło
3
Sprytne, ale co, jeśli istnieją 2 lub więcej obiektów KeyValue zawierających tę samą wartość? Który klucz należy wybrać?
Vineet Reynolds,
2
@Vineet, nie rozumiem, w jaki sposób to podejście rozwiązuje pytanie PO. co miałeś na myśli przez „Zatem, kiedy masz wartość, masz również klucz.”?
Qiang Li
9

Myślę, że to najlepsze rozwiązanie, oryginalny adres: Java2s

    import java.util.HashMap;
    import java.util.Map;

        public class Main {

          public static void main(String[] argv) {
            Map<String, String> map = new HashMap<String, String>();
            map.put("1","one");
            map.put("2","two");
            map.put("3","three");
            map.put("4","four");

            System.out.println(getKeyFromValue(map,"three"));
          }


// hm is the map you are trying to get value from it
          public static Object getKeyFromValue(Map hm, Object value) {
            for (Object o : hm.keySet()) {
              if (hm.get(o).equals(value)) {
                return o;
              }
            }
            return null;
          }
        }

Łatwe użycie: jeśli umieścisz wszystkie dane w hasMap i masz item = "Automobile", to szukasz klucza w hashMap. to dobre rozwiązanie.

getKeyFromValue(hashMap, item);
System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item));
chłopiec
źródło
7

Obawiam się, że będziesz musiał po prostu powtórzyć swoją mapę. Najkrócej mogłem wymyślić:

Iterator<Map.Entry<String,String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
    Map.Entry<String,String> entry = iter.next();
    if (entry.getValue().equals(value_you_look_for)) {
        String key_you_look_for = entry.getKey();
    }
}
André van Toly
źródło
6
for(int key: hm.keySet()) {
    if(hm.get(key).equals(value)) {
        System.out.println(key); 
    }
}
użytkownik309309
źródło
6

Wydaje się, że najlepszym sposobem jest iteracja wpisów, map.entrySet()ponieważ map.containsValue()prawdopodobnie i tak to robi.

Jonas K
źródło
Tak, właśnie to robi. Ale oczywiście zwraca true, gdy tylko znajdzie jedną wartość, dla której .equals jest prawdziwe, w przeciwieństwie do tego, co OP prawdopodobnie będzie musiał zrobić.
CPerkins
1
Cóż, iteracja wpisów może powrócić z kluczem, gdy tylko znajdzie pasującą wartość. Wiele meczów nie wydawało się problemem.
Jonas K
6

W przypadku interfejsu API do programowania rozwojowego Androida <19, rozwiązanie relacji jeden-do-jednego Vitalii Fedorenko nie działa, ponieważ Objects.equalsnie zostało zaimplementowane. Oto prosta alternatywa:

public <K, V> K getKeyByValue(Map<K, V> map, V value) {
    for (Map.Entry<K, V> entry : map.entrySet()) {
            if (value.equals(entry.getValue())) {
            return entry.getKey();
        }
    }
    return null;
}
Berga
źródło
To rozwiązanie działa dla mnie; opracowuję także dla archeologicznej wersji Androida, w moim przypadku, aby klucz znacznika mapy Google był przechowywany na mapie w wydarzeniu „onMarkerClick”. Iterowanie wpisu działa; ale iteracja kluczy i dopasowywanie ich do pozycji za pomocą get () oraz porównywanie danych wyjściowych nie, nie.
Toby Wilson
3

Możesz skorzystać z poniższych:

public class HashmapKeyExist {
    public static void main(String[] args) {
        HashMap<String, String> hmap = new HashMap<String, String>();
        hmap.put("1", "Bala");
        hmap.put("2", "Test");

        Boolean cantain = hmap.containsValue("Bala");
        if(hmap.containsKey("2") && hmap.containsValue("Test"))
        {
            System.out.println("Yes");
        }
        if(cantain == true)
        {
            System.out.println("Yes"); 
        }

        Set setkeys = hmap.keySet();
        Iterator it = setkeys.iterator();

        while(it.hasNext())
        {
            String key = (String) it.next();
            if (hmap.get(key).equals("Bala"))
            {
                System.out.println(key);
            }
        }
    }
}
Balasubramanian Ganapathi
źródło
Fajnie jest, że chcesz dostarczyć użytecznych rzeczy, ale nie powinna to być odpowiedź „tylko kodowa”, a sam kod nie powinien być pełen zapachów kodu.
Tom
2

Tak, musisz przeglądać skrót, chyba że zaimplementujesz coś zgodnie z sugestiami tych różnych odpowiedzi. Zamiast bawić się z entrySet, po prostu wezmę keySet (), przejdę przez ten zestaw i zatrzymam (pierwszy) klucz, który zapewni ci pasującą wartość. Jeśli potrzebujesz wszystkich kluczy pasujących do tej wartości, oczywiście musisz zrobić wszystko.

Jak sugeruje Jonas, może to już robić metoda zawieraValue, więc możesz po prostu pominąć ten test i wykonać iterację za każdym razem (a może kompilator już wyeliminuje nadmiarowość, kto wie).

Również w stosunku do innych odpowiedzi, jeśli wygląda odwrotna mapa

Map<Value, Set<Key>>

możesz poradzić sobie z nietypowymi mapowaniami klucz> wartość, jeśli potrzebujesz tej możliwości (rozplątując je na bok). To by dobrze włączyło do każdego z rozwiązań, które ludzie sugerują tutaj przy użyciu dwóch map.

Carl
źródło
2

Możesz uzyskać klucz, używając wartości, używając następującego kodu ...

ArrayList valuesList = new ArrayList();
Set keySet = initalMap.keySet();
ArrayList keyList = new ArrayList(keySet);

for(int i = 0 ; i < keyList.size() ; i++ ) {
    valuesList.add(initalMap.get(keyList.get(i)));
}

Collections.sort(valuesList);
Map finalMap = new TreeMap();
for(int i = 0 ; i < valuesList.size() ; i++ ) {
    String value = (String) valuesList.get(i);

    for( int j = 0 ; j < keyList.size() ; j++ ) {
        if(initalMap.get(keyList.get(j)).equals(value)) {
            finalMap.put(keyList.get(j),value);
        }   
    }
}
System.out.println("fianl map ---------------------->  " + finalMap);
Amit
źródło
2
public static class SmartHashMap <T1 extends Object, T2 extends Object> {
    public HashMap<T1, T2> keyValue;
    public HashMap<T2, T1> valueKey;

    public SmartHashMap(){
        this.keyValue = new HashMap<T1, T2>();
        this.valueKey = new HashMap<T2, T1>();
    }

    public void add(T1 key, T2 value){
        this.keyValue.put(key, value);
        this.valueKey.put(value, key);
    }

    public T2 getValue(T1 key){
        return this.keyValue.get(key);
    }

    public T1 getKey(T2 value){
        return this.valueKey.get(value);
    }

}
margines
źródło
Myślę, że odpowiedź można poprawić, dodając wyjaśnienie.
Jonathan
2
-1. Testowałem to z Stringkluczem i wartością. Kiedy dzwonię map.add("1", "2"); map.add("1","3");, mogę dzwonić map.getKey("2");i odbierać "1", nawet jeśli "1"jest to klucz do "3".
jlordo
@Jathanathan ideą tej klasy jest utrzymanie kolejnej mapy HashMap z odwrotnymi mapowaniami, aby oprócz pobierania wartości z klucza można było również pobrać klucz z wartości. Klasy T1 i T2 są nieco mylące; może zamiast tego nazwać je dosłownie kluczem i wartością? Chociaż oczekiwałbym możliwości otrzymania więcej niż jednej wartości lub więcej niż jednego klucza w zamian, w zależności od danych i tego, czego chcesz. Używaj ostrożnie
Chicowitz,
1
@theknightwhosaysni „1” nie jest już kluczem do „2” (już). Jest to również odpowiedź na twoje pytanie, połączenie getValue("1")powróci 3.
jlordo
Przepraszamy jlordo, pomyliłem się co do standardowego zachowania Hashmap: masz rację, że dodanie nowej wartości dla klucza powinno zastąpić starą wartość
Chicowitz
2

W java8

map.entrySet().stream().filter(entry -> entry.getValue().equals(value))
    .forEach(entry -> System.out.println(entry.getKey()));
użytkownik3724331
źródło
2
public static String getKey(Map<String, Integer> mapref, String value) {
    String key = "";
    for (Map.Entry<String, Integer> map : mapref.entrySet()) {
        if (map.getValue().toString().equals(value)) {
            key = map.getKey();
        }
    }
    return key;
}
Amazing India
źródło
Map <String, Integer> map = new HashMap <String, Integer> (); map.put („A”, 1); map.put („B”, 2); map.put („C”, 3); map.put („D”, 4); // System.out.println (mapa); System.out.println (getKey (mapa, „4”));
Amazing India
1
Co się stanie, jeśli wiele kluczy ma tę samą wartość?
Cà phê đen
Po przekazaniu wielu kluczy ma tę samą wartość, otrzymamy ostatni klucz jako wynik. przykład: wyjście A 1, B 1, C 1, D 2: jeśli przekażemy wartość 1, wyjście wyniesie C
Amazing India
@AmazingIndia Nie jest to gwarantowane i całkowicie zależy od konkretnej implementacji mapy. Na przykład HashMap nie gwarantuje zamówienia, więc nie masz pojęcia, jakie dane wyjściowe zostaną tu zwrócone.
Niels Doucet,
1
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class ValueKeysMap<K, V> extends HashMap <K,V>{
    HashMap<V, Set<K>> ValueKeysMap = new HashMap<V, Set<K>>();

    @Override
    public boolean containsValue(Object value) {
        return ValueKeysMap.containsKey(value);
    }

    @Override
    public V put(K key, V value) {
        if (containsValue(value)) {
            Set<K> keys = ValueKeysMap.get(value);
            keys.add(key);
        } else {
            Set<K> keys = new HashSet<K>();
            keys.add(key);
            ValueKeysMap.put(value, keys);
        }
        return super.put(key, value);
    }

    @Override
    public V remove(Object key) {
        V value = super.remove(key);
        Set<K> keys = ValueKeysMap.get(value);
        keys.remove(key);
        if(keys.size() == 0) {
           ValueKeysMap.remove(value);
        }
        return value;
    }

    public Set<K> getKeys4ThisValue(V value){
        Set<K> keys = ValueKeysMap.get(value);
        return keys;
    }

    public boolean valueContainsThisKey(K key, V value){
        if (containsValue(value)) {
            Set<K> keys = ValueKeysMap.get(value);
            return keys.contains(key);
        }
        return false;
    }

    /*
     * Take care of argument constructor and other api's like putAll
     */
}
Kanagavelu Sugumar
źródło
1
/**
 * This method gets the Key for the given Value
 * @param paramName
 * @return
 */
private String getKeyForValueFromMap(String paramName) {
    String keyForValue = null;
    if(paramName!=null)) {
        Set<Entry<String,String>> entrySet = myMap().entrySet();
        if(entrySet!=null && entrySet.size>0) {
            for(Entry<String,String> entry : entrySet) {
                if(entry!=null && paramName.equalsIgnoreCase(entry.getValue())) {
                    keyForValue = entry.getKey();
                }
            }
        }
    }
    return keyForValue;
}
kanaparthikiran
źródło
1
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class M{
public static void main(String[] args) {

        HashMap<String, List<String>> resultHashMap = new HashMap<String, List<String>>();

        Set<String> newKeyList = resultHashMap.keySet();


        for (Iterator<String> iterator = originalHashMap.keySet().iterator(); iterator.hasNext();) {
            String hashKey = (String) iterator.next();

            if (!newKeyList.contains(originalHashMap.get(hashKey))) {
                List<String> loArrayList = new ArrayList<String>();
                loArrayList.add(hashKey);
                resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
            } else {
                List<String> loArrayList = resultHashMap.get(originalHashMap
                        .get(hashKey));
                loArrayList.add(hashKey);
                resultHashMap.put(originalHashMap.get(hashKey), loArrayList);
            }
        }

        System.out.println("Original HashMap : " + originalHashMap);
        System.out.println("Result HashMap : " + resultHashMap);
    }
}
Madhav
źródło
1

Użyj cienkiego opakowania: HMap

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class HMap<K, V> {

   private final Map<K, Map<K, V>> map;

   public HMap() {
      map = new HashMap<K, Map<K, V>>();
   }

   public HMap(final int initialCapacity) {
      map = new HashMap<K, Map<K, V>>(initialCapacity);
   }

   public boolean containsKey(final Object key) {
      return map.containsKey(key);
   }

   public V get(final Object key) {
      final Map<K, V> entry = map.get(key);
      if (entry != null)
         return entry.values().iterator().next();
      return null;
   }

   public K getKey(final Object key) {
      final Map<K, V> entry = map.get(key);
      if (entry != null)
         return entry.keySet().iterator().next();
      return null;
   }

   public V put(final K key, final V value) {
      final Map<K, V> entry = map
            .put(key, Collections.singletonMap(key, value));
      if (entry != null)
         return entry.values().iterator().next();
      return null;
   }
}
Jayen
źródło
1

Moje 2 centy. Możesz dostać klucze do tablicy, a następnie przejść przez nią. Wpłynie to na wydajność tego bloku kodu, jeśli mapa jest dość duża, w której najpierw dostajesz klucze do tablicy, co może zająć trochę czasu, a następnie zapętlasz. W przeciwnym razie w przypadku mniejszych map powinno być w porządku.

String[] keys =  yourMap.keySet().toArray(new String[0]);

for(int i = 0 ; i < keys.length ; i++){
    //This is your key    
    String key = keys[i];

    //This is your value
    yourMap.get(key)            
}
Manu Bhat
źródło
I dlaczego ktoś miałby stosować takie podejście? Jak już powiedziałeś, wydajność byłaby gorsza niż w innych podejściach.
Tom
1

Myślę, że keySet () może dobrze znaleźć klucze mapowane na wartość i mieć lepszy styl kodowania niż entrySet () .

Dawny:

Załóżmy, że masz mapę HashMap , ArrayList res , wartość, dla której chcesz znaleźć wszystkie mapowanie kluczy , a następnie przechowuj klucze w res .

Możesz napisać kod poniżej:

    for (int key : map.keySet()) {
        if (map.get(key) == value) {
            res.add(key);
        }
    }

zamiast korzystać z entrySet () poniżej:

    for (Map.Entry s : map.entrySet()) {
        if ((int)s.getValue() == value) {
            res.add((int)s.getKey());
        }
    }

Mam nadzieję, że to pomoże :)

FrancisGeek
źródło
map.get(key) == valuenie jest dobrym pomysłem podczas sprawdzania równości obiektów, ponieważ porównujesz odniesienia. Równość obiektów powinna zawsze używać ich.equals()
frododot
1

Chociaż nie odpowiada to bezpośrednio na pytanie, jest powiązane.

W ten sposób nie musisz ciągle tworzyć / iterować. Po prostu stwórz odwrotną mapę raz i zdobądź to, czego potrzebujesz.

/**
 * Both key and value types must define equals() and hashCode() for this to work.
 * This takes into account that all keys are unique but all values may not be.
 *
 * @param map
 * @param <K>
 * @param <V>
 * @return
 */
public static <K, V> Map<V, List<K>> reverseMap(Map<K,V> map) {
    if(map == null) return null;

    Map<V, List<K>> reverseMap = new ArrayMap<>();

    for(Map.Entry<K,V> entry : map.entrySet()) {
        appendValueToMapList(reverseMap, entry.getValue(), entry.getKey());
    }

    return reverseMap;
}


/**
 * Takes into account that the list may already have values.
 * 
 * @param map
 * @param key
 * @param value
 * @param <K>
 * @param <V>
 * @return
 */
public static <K, V> Map<K, List<V>> appendValueToMapList(Map<K, List<V>> map, K key, V value) {
    if(map == null || key == null || value == null) return map;

    List<V> list = map.get(key);

    if(list == null) {
        List<V> newList = new ArrayList<>();
        newList.add(value);
        map.put(key, newList);
    }
    else {
        list.add(value);
    }

    return map;
}
Markymark
źródło
0

Ważne jest, aby pamiętać, że ponieważ to pytanie, Apache Collections obsługuje ogólne BidiMaps . Dlatego niektóre z najczęściej głosowanych odpowiedzi nie są już dokładne w tym punkcie.

W przypadku serializowanej usługi BidiMap, która obsługuje również zduplikowane wartości (scenariusz jeden do wielu), rozważ także MapDB.org .

Kervin
źródło
0
  1. Jeśli chcesz uzyskać klucz od wartości, najlepiej użyć bidimapy (mapy dwukierunkowe), możesz uzyskać klucz od wartości w czasie O (1).

    Wadą tego rozwiązania jest to, że można używać tylko unikatowego zestawu kluczy i zestawu wartości.

  2. W Javie istnieje struktura danych o nazwie Tabela , która jest niczym innym jak mapą podobnych map

    Tabela <A, B, C> == mapa <A, mapa <B, C>>

    Tutaj można uzyskać map<B,C>, wysyłając zapytanie T.row(a);, a także można uzyskać map<A,C>, wysyłając zapytanieT.column(b);

W twoim specjalnym przypadku wstaw C jako pewną stałą.

Czyli jak <a1, b1, 1> <a2, b2, 1>, ...

Więc jeśli znajdziesz poprzez T.row (a1) ---> zwraca mapę z -> pobierz zestaw kluczy to zwrócona mapa.

Jeśli musisz znaleźć wartość klucza, T.column (b2) -> zwraca mapę z -> pobierz zestaw kluczy z zwróconej mapy.

Zalety w stosunku do poprzedniego przypadku:

  1. Może używać wielu wartości.
  2. Bardziej wydajne przy użyciu dużych zestawów danych.
Ordynans
źródło