0

I'm having a BiMap with a String as key and an array of Strings as value. Now i'm trying to get with a single String (which is part of the value array) the key.

private static BiMap<String, String[]> map = ImmutableBiMap.<String, String[]>builder().build();
static {
    map.put("000", new String[] {"CH", "CHE", "Switzerland"});
    map.put("001", new String[] {"US", "USA", "United States of America"});
    map.put("002", new String[] {"IT", "ITA", "Italy"});
}

And in the next method i'm trying to search with "CH" to get "000" (which does not work).

private static String getKey(Map<String,String[]> map, String find) {
    Map<String[], String> inversedMap = map.inverse();
    if(inversedMap.containsKey() {
        return inversedMap.get(find);
    }
    return null;
}

Is there a way to 'find' the key like this, without that i need to search with an array like this: String[] find = new String[] {"CH", "CHE", "Switzerland"};

All the values and keys are unique, so there is expected only a single result. And i'm searching always for the first value in the array, f.ex. "CH" or "US".

LucBBC
  • 29
  • 3
  • What if many arrays contain same value? List of keys should be returned or any first found? – Michał Krzywański Sep 12 '19 at 06:11
  • @michalk yes i forgot to mention sorry. All the keys and values are unique. So there is expected a single result. Additionally i'm searching always for the first value (f.ex. "CH" or "US" or "IT"). – LucBBC Sep 12 '19 at 06:18
  • The lookup wouldn't work even if you did write `String[] find = new String[] {"CH", "CHE", "Switzerland"}`, the lookup wouldn't work, because arrays just use the default `Object.equals`, which means that two separate arrays are never "equal" even if they contain the same elements. – ruakh Sep 12 '19 at 06:27

2 Answers2

2

No, there is no way to find the key like you want. You have to either change the way you store the data to support all the different lookup method you need or go through all keys one by one (at which point making an inverse map makes no sense an you can just go through the Map entries).

A trivial approach would be a purpose built class that contains several maps.

Torben
  • 3,805
  • 26
  • 31
  • Yes this would be fine too, it basically is just a testing class. The value we get from a service which implemented the logic already. We just need to mock this service. @Torben – LucBBC Sep 12 '19 at 06:37
1

In case you have a case to find smth. by value (not by key) then you could use for loop in case you do not worry about performance. Otherwise, you should wrap this BiMap with a wrapper and add addtional Map with val -> key:

public final class CountryCache {

    private final Map<String, String[]> codeNames = new HashMap<>();
    private final Map<String, String> nameCode = new HashMap<>();

    {
        codeNames.put("000", new String[] { "CH", "CHE", "Switzerland" });
        codeNames.put("001", new String[] { "US", "USA", "United States of America" });
        codeNames.put("002", new String[] { "IT", "ITA", "Italy" });

        codeNames.forEach((code, names) -> Arrays.stream(names).forEach(name -> nameCode.put(name, code)));
    }

    private static final CountryCache INSTANCE = new CountryCache();

    public static CountryCache getInstance() {
        return INSTANCE;
    }

    private CountryCache() {
    }

    public String findByName(String name) {
        return nameCode.get(name);
    }

}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35