2013-04-19 2 views
17

В какой-то момент в моем коде я создал Set<Map.Entry<K, V>> с карты. Теперь я хочу воссоздать одну и ту же картографическую форму, поэтому я хочу преобразовать HashSet<Map.Entry<K, V>> в HashMap<K, V>. У Java есть собственный вызов для этого, или мне нужно перебирать установленные элементы и строить карту вручную?Convert Set <Map.Entry <K, V>> to HashMap <K, V>

+0

Как вы создали '' Set' из Map', используя ключ или значение или пользовательской логики? кроме того, для 'HashSet''' HashMap' не существует 'native' метода. Вам нужно повторить и использовать некоторую логику, как при вводе в «HashMap», как вы выбираете ключ и значение. – harsh

+0

@Paul теперь вопрос дает ясный смысл – harsh

+1

Я не думаю, что «Map.Entry» предназначен для использования таким образом. Использует ли реализация, используемая 'HashMap' переопределить' hashCode' и 'equals', например? –

ответ

17

В java нет встроенного API для прямого преобразования между HashSet и HashMap, вам необходимо выполнить итерацию по набору и используя Entry заполнить карту.

один подход:

Map<Integer, String> map = new HashMap<Integer, String>(); 
    //fill in map 
    Set<Entry<Integer, String>> set = map.entrySet(); 

    Map<Integer, String> mapFromSet = new HashMap<Integer, String>(); 
    for(Entry<Integer, String> entry : set) 
    { 
     mapFromSet.put(entry.getKey(), entry.getValue()); 
    } 

Хотя то, что цель здесь, если вы делаете какие-либо изменения в Set, которые также будут отражены в Map как набор возвращенного Map.entrySet является резервное копирование с помощью Map. См javadoc ниже:

< Установить запись < Integer, String >> java.util.Map.entrySet()

Возвращает представление набора отображений содержится в этой карте. Набор , подкрепленный картой, поэтому изменения на карте отражаются в наборе, а - наоборот. Если карта изменена, когда итерация по набору выполняется (за исключением операции собственного удаления итератора или через операцию setValue в записи карты, возвращаемой итератором ), результаты итерации не определены. Набор поддерживает удаление элемента , которое удаляет соответствующее сопоставление с карты, с помощью операций Iterator.remove, Set.remove, removeAll, retainAll и clear . Он не поддерживает операции add или addAll.

1

Довольно короткое Java 8 решение. Может справляться с дублирующимися ключами.

Map<Integer, String> map = new HashMap<>(); 
    //fill in map 
    Set<Map.Entry<Integer, String>> set = map.entrySet(); 
    Map<Integer, String> mapFromSet = set.stream().collect(Collectors.toMap(Entry::getKey, 
     Entry::getValue, 
     (a,b)->b)); 

Edit: благодаря shmosel, который заслуживает большего кредита, чем я для этого

+0

Нет. Ваш BiConsumer не объединяет Карты. – Joe

+0

В приведенном выше коде метод accept BiConsumer никогда не вызывается. Я бы предпочел использовать null, но метод сбора глупо выбрасывает NPE в этом случае. – mikeyreilly

+1

@mikeyreilly, [документация] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#collect-java.util.function.Supplier-java.util .function.BiConsumer-java.util.function.BiConsumer-) явно не говорит, что объединитель никогда не вызывается для последовательного потока. Таким образом, вы просто нарушаете договор метода. –

0

В Java 8 с правильным объединителя

Map<Integer, String> map = new HashMap<>(); 
//fill in map 
Set<Map.Entry<Integer, String>> set = map.entrySet(); 

Map<Integer, String> mapFromSet =set.stream().collect(HashMap::new,(t, u) -> t.put(u.getKey(), u.getValue()), 
(Map mapToReturn, Map otherMap) -> 
    { 
     otherMap.entrySet().forEach((Map.Entry entry) -> { 
      mapToReturn.put(entry.getKey(),entry.getValue()); 
     }); 
     return mapToReturn;});); 
26

Simpler Java-8 решение с Collectors.toMap:

Map<Integer, String> mapFromSet = set.stream() 
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); 

IllegalStateException будет выброшен, если d встречается ключевой элемент.

+0

Какие aboug NPE, если какое-либо значение равно нулю? –

0

На Java 9, мы имеем Map.ofEntries. Они берут записи только как массив, поэтому вам нужно сначала преобразовать их с toArray() и выбросить информацию о типе.

@SuppressWarnings("unchecked") 
(Map.Entry<K, V>[] array = entrySet.toArray((Map.Entry<K, V>[])new Map.Entry<?, ?>[entrySet.size()]); 
Map<K, V> map = Map.ofEntries(array); 

Apache Commons имеет аналогичные методы.Commons Ланг ArrayUtils.toMap:

Map<Object, Object> map = ArrayUtils.toMap(entrySet.toArray()); 

// to recover the type... 
@SuppressWarnings("unchecked") 
Map<K, V> typedMap = (Map<K, V>)(Map<?, ?>)map; 

Commons Коллекции MapUtils.putAll:

Map<K, V> map = MapUtils.putAll(new HashMap<K, V>(), entrySet.toArray());