Java Hashmap: วิธีรับคีย์จากค่า


451

หากฉันมีค่า"foo"และ a HashMap<String> ftwที่ftw.containsValue("foo")ส่งคืนtrueฉันจะรับคีย์ที่เกี่ยวข้องได้อย่างไร ฉันต้องวนซ้ำ hashmap หรือไม่ วิธีที่ดีที่สุดในการทำเช่นนั้นคืออะไร?


72
โปรดทราบว่าไม่มีคีย์ที่เกี่ยวข้องเดียว - อาจมีการแมปหลายคีย์เป็นค่าเดียวกัน
CPerkins

1
@ CPerkins แต่สำหรับ hashmaps เช่น <strFilename, Reader> และอื่น ๆ อีกมากมาย 1 ต่อ 1 มันมีประโยชน์มาก
กุมภ์อำนาจ

หากคุณมีรายการเล็ก ๆ น้อย ๆ ลองพิจารณาสร้างค่าคงที่ public static final String TIME = "time";และproperties.put(TIME, PbActivityJpa_.time);
Basheer AL-MOMANI

อาจช่วยให้คุณได้รับข้อมูลจากแผนที่และคุณสามารถทำการประมวลผลได้เช่นกัน frugalisminds.com/java/java-8-stream-map-examples
Sanjay-Dev

คำตอบ:


215

หากคุณเลือกใช้ไลบรารี Commons Collectionsแทนที่จะเป็น Java Collections API มาตรฐานคุณสามารถทำสิ่งนี้ได้อย่างง่ายดาย

BidiMapอินเตอร์เฟซในห้องสมุดคอลเลกชันคือแผนที่สองทิศทางที่ช่วยให้คุณสามารถแผนที่สำคัญในการค่า (เช่นแผนที่ปกติ) และยังรวมไปถึงแมมูลค่าให้กับคีย์จึงช่วยให้คุณสามารถดำเนินการค้นหาในทั้งสองทิศทาง ได้รับที่สำคัญสำหรับค่าได้รับการสนับสนุนโดยgetKey () วิธีการ

มีข้อแม้แม้ว่าแผนที่ bidi ไม่สามารถมีค่าหลายค่าที่แมปไปยังคีย์และดังนั้นถ้าชุดข้อมูลของคุณมีการแมป 1: 1 ระหว่างคีย์และค่าคุณจะไม่สามารถใช้ bidimaps ได้

ปรับปรุง

หากคุณต้องการใช้ Java Collections API คุณจะต้องตรวจสอบให้แน่ใจว่ามีความสัมพันธ์ 1: 1 ระหว่างคีย์และค่าในเวลาที่ใส่ค่าลงในแผนที่ พูดง่ายกว่าทำ

เมื่อคุณมั่นใจได้แล้วให้ใช้เมธอด entrySet ()เพื่อรับชุดของรายการ (การแมป) ในแผนที่ เมื่อคุณได้รับชุดชนิดที่เป็นMap.Entryให้ทำซ้ำผ่านรายการเปรียบเทียบค่าที่เก็บไว้กับที่คาดไว้และรับคีย์ที่เกี่ยวข้อง

อัปเดต # 2

การสนับสนุนสำหรับแผนที่ bidi พร้อมข้อมูลทั่วไปสามารถพบได้ในGoogle Guavaและห้องสมุดคอมมอนส์ - คอลเลกชันที่ได้รับการปรับโครงสร้างใหม่ (อันหลังไม่ใช่โครงการ Apache) ขอบคุณ Esko ที่ชี้ให้เห็นถึงการสนับสนุนทั่วไปที่ขาดหายไปใน Apache Commons Collections การใช้คอลเล็กชันที่มีข้อมูลทั่วไปทำให้รหัสที่บำรุงรักษาได้ดี


23
... และถ้าคุณชอบ Generics และทุกอย่างที่ทันสมัย ​​Google Collections มี BiMap ซึ่งคุณสามารถรับค่าการจับคู่คีย์ที่ระบุโดยการเรียก biMap.inverse (). get (value);
Esko

1
ใช่ Apache Commons Collections ไม่สนับสนุน generics อย่างไรก็ตามมี Google Collections ตามที่คุณได้ชี้ให้เห็น (ซึ่งฉันยังไม่ได้ใช้ - ยังไม่มีการเผยแพร่ 1.0) และมี Commons-Collections ที่ได้รับการปรับปรุงใหม่พร้อมการสนับสนุน Generics คุณจะพบว่านี่เป็นโครงการ Sourceforge @ sourceforge.net/projects/collections
Vineet Reynolds

2
Google Collections ไม่ใช่คอมมอนส์ - คอลเล็กชันที่ปรับปรุงใหม่
whiskysierra

12
@whisksierra: ฉันไม่คิดว่าจะมีใคร (ตอนนี้) พูดอย่างนั้น
อารมณ์เสีย

2
อาปาเช่คอลเลกชันนี้สนับสนุน generics commons.apache.org/proper/commons-collections/javadocs/...
Kervin

603

หากโครงสร้างข้อมูลของคุณมีการแมปหลายต่อหลายระหว่างคีย์และค่าคุณควรวนซ้ำรายการและเลือกคีย์ที่เหมาะสมทั้งหมด:

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

ในกรณีที่มีความสัมพันธ์แบบหนึ่งต่อหนึ่งคุณสามารถส่งคืนคีย์ที่ตรงกันแรก:

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

ใน Java 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());
}

นอกจากนี้สำหรับผู้ใช้ Guava BiMapอาจมีประโยชน์ ตัวอย่างเช่น:

BiMap<Token, Character> tokenToChar = 
    ImmutableBiMap.of(Token.LEFT_BRACKET, '[', Token.LEFT_PARENTHESIS, '(');
Token token = tokenToChar.inverse().get('(');
Character c = tokenToChar.get(token);

3
คุณสามารถพูดอะไรเกี่ยวกับการแสดงได้บ้าง? สิ่งที่จะได้รับการปรับให้เหมาะสมยิ่งขึ้น? นี่หรือ BidiMap?
tasomaniac

ฉันคิดว่าวิธีการแก้ปัญหาเดียวกันฉันได้ upvoting มันแน่นอน แต่ฉันสงสัยในประสิทธิภาพเมื่อมันมาถึงคอลเลกชันขนาดใหญ่จริงๆ
arjacsoh

3
stackoverflow.com/questions/4553624/hashmap-get-put-complexity HashMap o(1)มีความซับซ้อนเวลา หากคุณทำซ้ำค่ามากกว่านั้นก็จะฆ่าประสิทธิภาพ หากคุณต้องการbetter performanceและมีone-oneความสัมพันธ์คุณสามารถใช้another mapที่value is a key
veer7

3
ฉันขอแนะนำให้แทนที่.filter(entry -> entry.getValue().equals(value))ด้วยเนื่องจากไม่มีคำสั่งเกี่ยวกับความสามารถ นอกจากนี้คุณสามารถแทนที่ด้วย.filter(entry ->Objects.equals(entry.getValue(), value))null.map(entry -> entry.getKey()).map(Map.Entry::getKey)
Holger

ฉันมีปัญหาในการทำความเข้าใจสัญกรณ์ <T, E> ก่อนตั้งค่า <T> getKeysByValue () ... อะไรคือจุดสำคัญ .... วิธีที่แตกต่างในการทำโดยไม่ใช้มันคืออะไร? ขอบคุณ
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());
            }
        }
    }
}

ข้อมูลเพิ่มเติมบางอย่าง ... อาจเป็นประโยชน์กับคุณ

วิธีการข้างต้นอาจไม่ดีถ้า hashmap ของคุณใหญ่เกินไป หาก hashmap ของคุณมีคีย์ที่ไม่ซ้ำกันกับการจับคู่ค่าที่ไม่ซ้ำกันคุณสามารถรักษา hashmap เพิ่มเติมได้อีกหนึ่งรายการที่มีการทำแผนที่จาก Value to Key

นั่นคือคุณต้องรักษาแฮชแมพสองอัน

1. Key to value

2. Value to key 

ในกรณีนี้คุณสามารถใช้ hashmap ที่สองเพื่อรับรหัส


19

ฉันคิดว่าตัวเลือกของคุณคือ

  • ใช้การนำแผนที่ไปใช้เพื่อสิ่งนี้เช่นBiMapจากคอลเลกชัน google โปรดทราบว่า Google BiMap ของคอลเลกชันต้องใช้ค่าที่ไม่ซ้ำกันเช่นเดียวกับคีย์ แต่มันมีประสิทธิภาพสูงในการทำงานทั้งสองทิศทาง
  • บำรุงรักษาแผนที่สองแบบด้วยตนเอง - หนึ่งแผนที่สำหรับคีย์ -> ค่าและอีกแผนที่สำหรับค่า -> คีย์
  • ทำซ้ำผ่านentrySet()และเพื่อค้นหาคีย์ที่ตรงกับค่า นี่เป็นวิธีที่ช้าที่สุดเนื่องจากต้องการการวนซ้ำทั้งชุดในขณะที่อีกสองวิธีไม่ต้องการ

19

คุณสามารถแทรกทั้งคีย์คู่ค่าและผกผันลงในโครงสร้างแผนที่ของคุณ

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

การใช้ map.get ("theValue") จะส่งคืน "theKey"

มันเป็นวิธีที่รวดเร็วและสกปรกที่ฉันทำแผนที่คงที่ซึ่งจะใช้ได้กับชุดข้อมูลบางตัวเท่านั้น:

  • มีเพียง 1 ถึง 1 คู่
  • ชุดของค่าต่างกันจากชุดของคีย์ (1-> 2, 2-> 3 แบ่งออก)

4
มันไม่ถูกต้องจริงๆ สิ่งนี้ไม่เพียงต้องการ 1-1 เท่านั้น แต่ยังรวมถึงชุดของค่าที่แยกจากชุดของคีย์ คุณไม่สามารถใช้สิ่งนี้กับแผนที่ bijective {1 -> 2, 2 -> 3}: 2 เป็นทั้งค่าและคีย์
Luis A. Florit

15

ตกแต่งแผนที่ด้วยการติดตั้งของคุณเอง

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

ฉันคิดว่านี่เป็นวิธีที่น่าสนใจ แต่เนื่องจากความสัมพันธ์ต้องเป็น 1: 1 ฉันจะกำจัด HashMap ไปด้วยกันและใช้อินเทอร์เฟซ Map <K, V> แทนเพื่อหลีกเลี่ยงการซ้ำซ้อนทั้งค่าและกุญแจ
Fran Marzoa

11

ไม่มีคำตอบที่ชัดเจนเนื่องจากหลายปุ่มสามารถจับคู่กับค่าเดียวกัน หากคุณบังคับใช้รหัสเฉพาะของคุณเองทางออกที่ดีที่สุดคือการสร้างคลาสที่ใช้ Hashmaps สองตัวเพื่อติดตามการแมปในทั้งสองทิศทาง


11

เพื่อหากุญแจทั้งหมดว่าแผนที่จะคุ้มค่าที่ย้ำผ่านทุกคู่ใน HashMap map.entrySet()ใช้


4
วิธีนี้มีความเข้มข้นสูงมากจนถึงจุดที่ใช้งานไม่ได้กับ HashMaps ขนาดใหญ่
Joehot200

10

ใช้ Java 8:

ftw.forEach((key, value) -> {
    if (value.equals("foo")) {
        System.out.print(key);
    }
});

6
value=="foo" สิ่งนี้จะไม่ทำงาน equalsควรใช้เพื่อเปรียบเทียบสตริง
Anton Balaniuc

@Anton จริงเว้นแต่valueมีการฝึกงาน
frododot

9

หากคุณสร้างแผนที่ด้วยรหัสของคุณเองให้ลองใส่รหัสและค่าในแผนที่ด้วยกัน:

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

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

จากนั้นเมื่อคุณมีค่าคุณยังมีกุญแจ


3
ฉลาด แต่จะเกิดอะไรขึ้นถ้ามีวัตถุ KeyValue 2 ชิ้นขึ้นไปที่มีค่าเท่ากัน คีย์ใดที่ควรเลือก
Vineet Reynolds

2
@ ไวน์ฉันไม่เห็นว่าวิธีการนี้แก้คำถามของ OP ได้อย่างไร คุณหมายความว่าอย่างไรเมื่อคุณมีคุณค่าคุณมีกุญแจด้วย
Qiang Li

9

ฉันคิดว่านี่เป็นทางออกที่ดีที่สุดที่อยู่เดิม: 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;
          }
        }

การใช้งานง่าย: หากคุณใส่ข้อมูลทั้งหมดใน hasMap และคุณมี item = "รถยนต์" ดังนั้นคุณจึงมองหากุญแจใน hashMap นั่นเป็นทางออกที่ดี

getKeyFromValue(hashMap, item);
System.out.println("getKeyFromValue(hashMap, item): "+getKeyFromValue(hashMap, item));

7

ฉันเกรงว่าคุณจะต้องย้ำแผนที่ของคุณ สั้นที่สุดที่ฉันจะได้รับ:

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


6

ดูเหมือนว่าวิธีที่ดีที่สุดสำหรับคุณในการวนซ้ำรายการที่ใช้map.entrySet()เนื่องจากmap.containsValue()อาจเป็นเช่นนี้ต่อไป


ใช่นั่นคือสิ่งที่มันทำ แต่แน่นอนว่ามันจะกลับมาจริงทันทีที่พบค่าหนึ่งซึ่ง. equals เป็นความจริงซึ่งตรงข้ามกับสิ่งที่ OP จะต้องทำ
CPerkins

1
การวนซ้ำรายการสามารถส่งคืนด้วยรหัสทันทีที่พบค่าที่ตรงกัน การแข่งขันหลายรายการดูเหมือนจะไม่เป็นปัญหา
Jonas K

6

สำหรับ API เป้าหมายการพัฒนา Android <19 โซลูชันความสัมพันธ์แบบหนึ่งต่อหนึ่งของ Vitalii Fedorenko ไม่ทำงานเพราะObjects.equalsไม่ได้ใช้งาน นี่เป็นทางเลือกง่าย ๆ :

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

วิธีนี้ใช้ได้ผลสำหรับฉัน; ยังพัฒนาสำหรับรุ่น Android โบราณคดีในกรณีของฉันเพื่อรับคีย์ของเครื่องหมาย Google Map ที่จัดขึ้นในแผนที่ในเหตุการณ์ "onMarkerClick" การวนซ้ำรายการ setSet ทำงาน; แต่ทำซ้ำคีย์และจับคู่กับรายการด้วย get () และเปรียบเทียบผลลัพธ์ไม่ได้
Toby Wilson

3

คุณสามารถใช้ด้านล่าง:

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

เป็นเรื่องที่ดีที่คุณต้องการให้สิ่งที่มีประโยชน์ แต่ไม่ควรเป็นคำตอบ "รหัสเท่านั้น" และโค้ดเองก็ไม่ควรมีกลิ่นของโค้ดเช่นกัน
ทอม

2

ใช่คุณต้องวนซ้ำ hashmap เว้นแต่คุณจะใช้บางสิ่งตามคำแนะนำที่หลากหลายเหล่านี้ แทนที่จะเล่นซอกับ entrySet ฉันจะได้รับชุดคีย์ () วนซ้ำชุดนั้นและเก็บคีย์ (ก่อน) ที่ทำให้คุณได้รับคุณค่าที่ตรงกัน หากคุณต้องการคีย์ทั้งหมดที่ตรงกับค่านั้นเห็นได้ชัดว่าคุณต้องทำทุกสิ่ง

ดังที่โจนัสแนะนำว่านี่อาจเป็นวิธีที่วิธี VVVueue กำลังทำอยู่ดังนั้นคุณอาจข้ามการทดสอบทั้งหมดมารวมกันและทำซ้ำทุกครั้ง (หรืออาจจะคอมไพเลอร์จะกำจัดความซ้ำซ้อน

นอกจากนี้เมื่อเทียบกับคำตอบอื่น ๆ หากแผนที่ย้อนกลับของคุณดูเหมือน

Map<Value, Set<Key>>

คุณสามารถจัดการกับการจับคู่คีย์ -> ค่าที่ไม่ซ้ำกันได้หากคุณต้องการความสามารถนั้น (แยกออกจากกัน) นั่นจะรวมสิ่งที่ดีลงในโซลูชันที่ผู้คนแนะนำที่นี่โดยใช้สองแผนที่


2

คุณสามารถรับรหัสโดยใช้ค่าโดยใช้รหัสต่อไปนี้

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

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

}

ฉันคิดว่าคำตอบนี้สามารถปรับปรุงได้โดยการเพิ่มคำอธิบาย
Jonathan

2
-1 ฉันทดสอบด้วยStringคีย์และค่า เมื่อผมเรียกmap.add("1", "2"); map.add("1","3");แล้วฉันสามารถเรียกmap.getKey("2");และเรียก"1"แม้ว่าจะเป็นกุญแจสำคัญสำหรับ"1" "3"
jlordo

@Jonathan แนวคิดที่อยู่เบื้องหลังคลาสนี้คือเก็บ HashMap อื่นไว้ด้วยการแม็พย้อนกลับเพื่อให้สามารถดึงค่าจากคีย์ได้นอกเหนือจากการเรียกคืนค่าจากคีย์แล้ว คลาส T1 & T2 นั้นค่อนข้างสับสน อาจตั้งชื่อคีย์และค่าอย่างแท้จริงแทน แม้ว่าฉันจะคาดหวังความสามารถในการรับค่ามากกว่าหนึ่งค่าหรือมากกว่าหนึ่งคีย์ในทางกลับกันขึ้นอยู่กับข้อมูลและสิ่งที่คุณต้องการ ใช้ด้วยความระมัดระวัง
Chicowitz

1
@theknightwhosaysni "1" ไม่ใช่กุญแจสำคัญสำหรับ "2" (อีกต่อไป) และนี่ก็เป็นคำตอบให้กับคำถามของคุณเรียกจะกลับมาgetValue("1") 3
jlordo

ขออภัย jlordo ฉันเข้าใจผิดเกี่ยวกับพฤติกรรม Hashmap มาตรฐาน: คุณถูกต้องแล้วว่าการเพิ่มค่าใหม่สำหรับคีย์ควรแทนที่ค่าเก่า
Chicowitz


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

แผนที่ <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 (แผนที่); System.out.println (getKey (แผนที่ "4"));
Amazing India

1
จะเกิดอะไรขึ้นถ้ามีหลายคีย์มีค่าเท่ากัน?
Càphêđen

เมื่อคุณผ่านหลายคีย์มีค่าเท่ากันเราจะได้รับคีย์สุดท้ายตามผลลัพธ์ ตัวอย่าง: เอาต์พุต 1, B 1, C 1, D 2: ถ้าเราผ่านค่า 1 เอาต์พุตจะเป็น C
Amazing India

@AmazingIndia สิ่งนี้ไม่รับประกันและขึ้นอยู่กับการนำแผนที่ไปใช้โดยเฉพาะ ตัวอย่างเช่น HashMap ไม่รับประกันการสั่งซื้อดังนั้นคุณจึงไม่ทราบว่าจะส่งคืนผลลัพธ์ใดที่นี่
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
     */
}

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

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

1

ใช้เสื้อคลุมบาง ๆ : 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;
   }
}

1

2 เซนต์ของฉัน คุณสามารถรับกุญแจในอาร์เรย์จากนั้นวนซ้ำผ่านอาร์เรย์ สิ่งนี้จะส่งผลต่อประสิทธิภาพของบล็อครหัสนี้หากแผนที่มีขนาดใหญ่มากซึ่งในที่ที่คุณได้รับกุญแจในอาเรย์ก่อนซึ่งอาจใช้เวลาพอสมควรแล้วคุณจะวนซ้ำ มิฉะนั้นสำหรับแผนที่ขนาดเล็กมันควรจะโอเค

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

และทำไมบางคนควรใช้วิธีการนั้น อย่างที่คุณพูดไปแล้วการแสดงจะแย่กว่าวิธีอื่น ๆ
Tom

1

ฉันคิดว่าkeySet ()อาจดีในการค้นหาการจับคู่คีย์กับค่าและมีรูปแบบการเข้ารหัสที่ดีกว่าentrySet ()()

Ex:

สมมติว่าคุณมีแผนที่ HashMap , ArrayListละเอียดเป็นค่าที่คุณต้องการค้นหาทั้งหมดกุญแจสำคัญในการทำแผนที่ไปแล้วเก็บกุญแจไปที่ความละเอียดสูง

คุณสามารถเขียนรหัสด้านล่าง:

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

แทนที่จะใช้ entrySet () ด้านล่าง:

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

หวังว่าจะช่วย :)


map.get(key) == valueไม่ใช่ความคิดที่ดีเมื่อตรวจสอบความเท่าเทียมกันของวัตถุในขณะที่คุณกำลังเปรียบเทียบการอ้างอิง ความเสมอภาคของวัตถุควรใช้.equals()
Frododot

1

แม้ว่าสิ่งนี้จะไม่ตอบคำถามโดยตรง แต่เกี่ยวข้องกัน

วิธีนี้คุณไม่จำเป็นต้องสร้าง / ทำซ้ำ เพียงสร้างแผนที่ย้อนกลับหนึ่งครั้งและรับสิ่งที่คุณต้องการ

/**
 * 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;
}

0

มันเป็นสิ่งสำคัญที่จะต้องทราบว่าตั้งแต่คำถามนี้อาปาเช่คอลเลกชันสนับสนุนทั่วไป BidiMaps ดังนั้นคำตอบที่ได้รับการโหวตไม่กี่ข้อจึงไม่แม่นยำอีกต่อไป

สำหรับ BidiMap ที่ทำให้เป็นอนุกรมที่รองรับค่าซ้ำกัน (1 ต่อหลายสถานการณ์) ให้พิจารณาMapDB.orgด้วย


0
  1. หากคุณต้องการรับรหัสจากค่าวิธีที่ดีที่สุดคือใช้ bidimap (แผนที่สองทิศทาง) คุณสามารถรับรหัสจากมูลค่าในเวลา O (1)

    แต่ข้อเสียเปรียบของสิ่งนี้คือคุณสามารถใช้ชุดคีย์และค่าที่ไม่ซ้ำกันได้เท่านั้น

  2. มีโครงสร้างข้อมูลที่เรียกว่าTableใน java ซึ่งไม่มีอะไรนอกจากแผนที่ของแผนที่เช่น

    ตาราง <A, B, C> == แผนที่ <A, แผนที่ <B, C>>

    ที่นี่คุณจะได้รับmap<B,C>จากการสอบถามT.row(a);และคุณยังสามารถรับได้map<A,C>โดยการสอบถามT.column(b);

ในกรณีพิเศษของคุณให้ใส่ C เป็นค่าคงที่

ดังนั้นมันเหมือนกับ <a1, b1, 1> <a2, b2, 1>, ...

ดังนั้นถ้าคุณค้นหาผ่าน T.row (a1) ---> ส่งคืนแผนที่ของ -> รับชุดคีย์แผนที่ที่ส่งคืนนี้

หากคุณต้องการหาค่าคีย์ดังนั้น T.column (b2) -> ส่งคืนแผนที่ของ -> รับชุดคีย์ของแผนที่ที่ส่งคืน

ข้อดีมากกว่ากรณีก่อนหน้า:

  1. สามารถใช้หลายค่า
  2. มีประสิทธิภาพมากขึ้นเมื่อใช้ชุดข้อมูลขนาดใหญ่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.