How to return a key if an element exists in List from Hash<String,List<Object>>?

c-an :

I need to get the key if the list in the key contains a specific value in it.

The way only I can think of is iterating the HashMap and also for loop for the List of each key's value and then check if the List contains the value and return the key. Something like this:

Map<String, List<MyItem>> map = new HashMap<>();
List<MyItem> list = new List<>();
list.add(new MyItem("Kim", 25);
list.add(new MyItem("Lee", 28);
map.put("Samsung", list);

String searchKeyWord = "Kim";
String myKey = getKeyByValue(map, searchKeyWord);

System.out.println("Found Key: " + myKey);

I don't know what's the best way is.

1.

public String getKeyByValue(Map<String, List<MyItem> map, String searchKeyWord) {
    boolean flag = false;
    String myKey = null;

    for (Entry<String, List<MyItem>> e : map.entrySet()) {
        String currentKey = e.getKey();
        List<MyItem> myItemList = e.getValue();
        Collections.sort(myItemList, this);
        for (int i = 0 ; i < myItemList.size() ; i++) {
            if (myItemList.get(i).name.equals(searchKeyWord)) {
                myKey = currentKey;
                flag = true;
            }
            if (flag) {
                break;
            }
        }
        if (flag) {
            break;
        }
    }
    return (flag ? myKey : null);
}

2.

public String getKeyByValue(Map map, String searchKeyWord){
    boolean flag = false;
    String myKey = null;

    for(Entry<String, List<MyItem>> e: map.entrySet()){
        String currentKey = e.getKey();
        List<MyItem> myItemList = e.getValue();
        Collections.sort(myItemList, this);
        if(binarySearch(myItemList, searchKeyWord)){
            myKey = currentKey;
            flag = true;
        }
    }

    if(flag) return myKey;
    else null;
}
  1. Using HashMap instead of List.
  2. Using Multi-value(Guava)

Or other methods...

Should I change the data structure? What's the best search algorithm for this?

Kartik :

Explanation in comments:

private static String getKeyByValue(Map<String, List<MyItem>> map, String searchKeyWord) {
    return map.entrySet().stream()      //all entries in the map
            .filter(e -> e.getValue().stream()
                    .anyMatch(i -> i.getName().equals(searchKeyWord))) //take only the ones which have searchKeyword in their list
            .findAny()                  //take just one such entry
            .map(Map.Entry::getKey)     //change Entry to String (the key)
            .orElse(null);              //if there is no such entry, return null
}

As @MCEmperor suggested, you can change String to Optional<String> return type and get rid of .orElse(null);.


Or if you have a lot of elements, you can avoid scanning the whole lists by using a data structure like Map<String, Map<String, MyItem>> like this:

Map<String, Map<String, MyItem>> m = new HashMap<>();

Map<String, MyItem> items = Map.of(
        "Kim", new MyItem("Kim", 25),
        "Lee", new MyItem("Lee", 28)
);

m.put("Samsung", items);

String result = m.entrySet().stream()
        .filter(e -> e.getValue().containsKey(searchKeyWord))
        .findAny()
        .map(Map.Entry::getKey)
        .orElse(null);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=147520&siteId=1