#java #loops #hashmap #contains
Вопрос:
У меня есть такая хэш-карта:
private HashMap<Integer, HashMap<String, Material>> logs = new HashMap<>();
Затем у меня есть несколько материалов, хранящихся в виде перечисления (например. Material.OAK_LOG
).
Есть ли простой способ проверить logs
, содержит ли хэш-карта хэш-карту с определенным материалом?
Я придумал это, и это работает, но я хочу знать, есть ли какой-либо другой способ сделать это без перебора всей хэш-карты
private boolean hasLog(Material mat){
boolean contains = false;
for (Map.Entry<Integer, HashMap<String, Material>> entry : this.logs.entrySet()) {
if(entry.getValue().containsValue(mat)){
contains = true;
break;
}
}
return contains;
}
Ответ №1:
Нет, вам придется перебирать карты, выполняя последовательный поиск.
Вы можете немного упростить логику , используя values()
вместо entrySet()
и просто return
напрямую, но это всего лишь незначительный рефакторинг:
private boolean hasLog(Material mat) {
for (HashMap<String, Material> submap : this.logs.values())
if (submap.containsValue(mat))
returns true;
return false;
}
Вы можете написать ту же логику, используя потоки Java 8 , но это тот же последовательный поиск вложенного цикла, поэтому сложность выполнения остается O(nm).
private boolean hasLog(Material mat) {
return this.logs.values().stream()
.anyMatch(submap -> submap.containsValue(mat));
}
Ответ №2:
Если ваши Material
объекты неизменяемы и уникальны с точки equals
зрения, вы можете использовать их в качестве ключа на карте перекрестных ссылок. Но если материал изменится, ваши карты могут быть повреждены в зависимости от того, как настроен equals.
Map<Material, String> crossRef = new HashMap<>();
Всякий раз, когда вы добавляете новую карту с материалом в журналы, выполните следующие действия:
int outerKey; = ... // some integer to get the inner map
String innerKey = .. // some string to get the actual Material
Map<String, Material> innerMap = logs.get(outerKey);
Material mat = new Material(...);
innerMap.put(innerKey, mat);
crossRef.put(mat, outerKey "_" innerKey);
Тогда позже
if (crossRef.contains(mat)) {
// it exists somewhere.
String mapId = crossRef.get(mat);
key[] parts = mapId.split("_");
int outerKey = Integer.valueOf(parts[0]);
String innerKey = parts[1];
Map<String, Material> map = logs.get(outerKey);
Material mat = map.get(innerKey);
}
Еще одним недостатком является то, что вы ускоряете время поиска за счет увеличения объема хранилища.
И еще раз подчеркнем, что если два разных материальных объекта будут сравниваться одинаково, они будут считаться дубликатами и, следовательно, не могут использоваться в качестве ключей для доступа к обоим типам материалов.
Вместо использования связанной строки в качестве ключа перекрестной ссылки вы можете использовать простой class
или record
содержащий их в качестве определенного типа.
Это был затянутый ответ на простой вопрос, но он может дать некоторые альтернативные идеи о том, как решить вашу проблему.