Удалить людей, имеющих одинаковые имена
Задача звучит так:
Создать словарь Map<String, String> занести в него десять записей по принципу «фамилия» - «имя». Удалить людей, имеющих одинаковые имена.
Мои вопросы:
Я видел готовое решение этой задачи, но думаю что его можно решить иным способом, не судите строго по коду, или по структуре кода, я только начинаю
У меня подчёркивается красным,
entrySet()(Выделил в коде), объясните пожалуйста, итератор можно вызывать наHashMapтолько один раз?, или же ошибка заключается в написании методов?
Код:
public class similarNameSurname {
public static void main(String[] args) {
createMap();
}
public static Map<String, String> createMap() {
Map<String, String> map = new HashMap<>();
map.put("Raj", "Baj");
map.put("Raq", "Ba");
map.put("Raw", "B");
map.put("Rae", "Faj");
map.put("Rar", "Baj");
return map;
}
private static void removeTheFirstNamesDuplicate(Map<String, String> map) {
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
ArrayList<String> names = new ArrayList<>();
while(iterator.hasNext()){
names.add(iterator.next().getValue());
}
}
private static void removeItemFromMapByValue(Map.Entry<String, String> map, ArrayList<String> list) {
Iterator<Map.Entry<String,String>> iterator1 = map.'entrySet()'.iterator();
while(iterator1.hasNext()){
int i = 0;
if(iterator1.next().getValue().equals(list.get(i))) {
iterator1.remove();
}
i++;
}
}
}
Ответы (2 шт):
Проблему с тем, что entrySet подчёркивается красным во втором методе, объяснил в комментарии @Byb -- в интерфейсе Map.Entry нет метода entrySet.
Также метод removeTheFirstNamesDuplicate выглядит какой-то промежуточной попыткой решения, в которой при помощи итератора создаётся список значений.
Однако основная задача состоит в том, чтобы найти дубликаты среди значений и удалить их. Поэтому не совсем понятно, зачем использовать итераторы и список для решения данной задачи.
Для поиска дубликатов можно либо построить карту частот, либо использовать два сета и то, что метод Set::add возвращает false при попытке добавить дубликат. (см. ответ на подобный вопрос Получить из строки только уникальные элементы).
Таким образом, сначала ищем сами дубликаты в коллекции значений (используя второй способ с двумя сетами), написав отдельный обобщённый (generic) метод:
public static <V> Set<V> findDuplicates(Collection<V> values) {
Set<V> uniques = new HashSet<>();
Set<V> dupes = new HashSet<>();
for (V value : values) {
if (!uniques.add(value)) {
dupes.add(value);
}
}
return dupes;
}
Тогда для удаления дублированных значений из мапы, обнаруженных при помощи метода findDuplicates, достаточно будет использовать стандартный метод Collection::removeAll, вызвав его для коллекции значений, возвращаемой методом Map::values:
Collection<V> values()
Returns aCollectionview of the values contained in this map. The collection is backed by the map, so changes to the map are reflected in the collection, and vice-versa. ... The collection supports element removal, which removes the corresponding mapping from the map, via theIterator.remove,Collection.remove,removeAll,retainAllandclearoperations.
Все изменения в данной коллекции будут отображаться в исходной мапе и наоборот. ... Коллекция поддерживает удаление элементов, что приведет к удалению соответствующего маппинга (пары "ключ" - "значение") из мапы...
Обобщённая реализация метода для удаления дубликатов из мапы может быть записана так ("однострочный" вариант):
public static <K, V> void removeDuplicateValues(Map<K, V> map) {
map.values().removeAll(findDuplicates(map.values()));
}
Тест:
Map<String, String> map = createMap();
System.out.println("Before: " + map);
removeDuplicateValues(map);
System.out.println("After: " + map);
Результат:
Before: {Rar=Baj, Raq=Ba, Rae=Faj, Raw=B, Raj=Baj}
After: {Raq=Ba, Rae=Faj, Raw=B}
удалены оба значения Baj.
объясните пожалуйста, итератор можно вызывать на
HashMapтолько один раз?
Iterator - это объект, который вызывается на коллекцию (у вас эта коллекция не Map, а та, которая возвращается после вызова map.enyrySet()). Каждый раз при вызове итератора создаётся новый объект, и ему все равно на какой коллекции он будет работать, причем разные итераторы ничего общего между собой не имеют, разве что шарят одну коллекцию, но она об этом ничего не знает. Так, что можете вызывать итератор столько раз, сколько захочется, только ошибку это не исправит.
А ошибка в том, что вы пытались вызвать итератор не на коллекцию Map, а на объект Map.Entry.
Измените код на
private static void removeItemFromMapByValue(Map<String, String> map, ArrayList<String> list) {