class BrazilianToponymMap {
  private final Map<String, List<String>> map;

  BrazilianToponymMap() {
    map = new BrazilianToponymMapLoader().buildMap();
  }

  // Since the actually toponym string is only a heuristic, it could be that we match more than we need, e.g.:
  // "Venho do Rio de Janeiro" will match, hungrily, the whole thing, rather than just "Rio de Janeiro".
  // To account for this, we loop, dropping the leftmost element of the toponym until we can't check any more.
  private <T> T toponymIter(String toponym, Function<String, T> processor, T defaultValue) {<FILL_FUNCTION_BODY>}

  public boolean isValidToponym(String toponym) {
    return toponymIter(toponym, toponymToCheck ->
        map.values().stream().anyMatch(list -> list.contains(toponymToCheck)) ? true : null,
      false);
  }

  public List<String> getStatesWithMunicipality(String toponym) {
    List<String> states = new ArrayList<>();
    map.forEach((state, municipalities) -> {
      if (municipalities.contains(toponym)) {
        states.add(state);
      }
    });
    return states;
  }

  public boolean isToponymInState(String toponym, String state) {
    List<String> municipalities = map.get(state);
    return municipalities != null && municipalities.contains(toponym);
  }
}

    String normalisedToponym = toponym.replace('-', ' ').toLowerCase();
    String[] toponymParts = normalisedToponym.split(" ");
    int toponymLength = toponymParts.length;
    for (int i = 0; i < toponymLength; i++) {
      String toponymToCheck = String.join(" ", Arrays.copyOfRange(toponymParts, i, toponymLength));
      T result = processor.apply(toponymToCheck);
      if (result != null) {
        return result;
      }
    }
    return defaultValue;
  
<no_super_class>