2010-07-15 2 views
5

Я создал класс Foo, который имеет метод toArray(), который возвращает Array<Int>.Итерация по HashMap HashMaps в Java (или Scala)

Теперь у меня есть сопоставление HashMap строк с HashMaps, которые отображают объекты в Foo. То есть:

HashMap<String,HashMap<Object,Foo>> 

И я хочу, чтобы создать новый объект типа:

HashMap<String,HashMap<Object,Array<Int>>> 

Это достигается путем вызова функции ToArray() для каждого элемента Foo в исходном HashMap.

Для этого я обычно бы сделать что-то вроде:

public static HashMap<String,HashMap<Object,Array<Int>>> changeMap(Map mpOld) { 
     Object key2; 
     String key1; 
     Iterator it2; 
     HashMap<String,HashMap<Object,Array<Int>>> mpNew= 
      new HashMap<String,HashMap<Object,Array<Int>>>() 
     Iterator it1 = mpOld.keySet().iterator(); 
     while (it1.hasNext()) { 
      key1=it1.next(); 
      it2= mpOld.get(key1).keySet().iterator(); 
      mpNew.put(key1,new HashMap<Object,Array<Int>>()) 
      while (it2.hasNext()) { 
       key2=it2.next(); 
       mpNew.get(key1).put(key2,mpOld.get(key1).get(key2).toArray()); 
       //TODO clear entry mpOld.get(key1).get(key2) 
      } 
      //TODO clear entry mpOld.get(key1) 
     } 
     return mpNew; 
    } 

Подобный код работает просто отлично, но Размер HashMap слишком большим, чтобы вместить два из них в памяти. Как вы можете видеть, я добавил два пункта, где я хочу очистить некоторые записи. Проблема в том, что если я это сделаю, я получаю либо ошибку параллелизма, либо цикл итератора просто завершается.

Интересно, есть ли лучший способ перебирать через Карты и копировать информацию.

Кроме того, я работаю в проекте Scala, но здесь я должен использовать типы Java для некоторых проблем с совместимостью. Хотя Java.util.HashMap не является итератором, может быть, у Скалы есть скрытая функциональность, чтобы справиться с этим?

Спасибо,

ответ

7

Итераторы предлагают remove(..) методы, которые безопасно удаляют ранее доступный элемент. Перебирайте элементы Key/Value на карте, преобразуя их и добавляя их на новую карту, и удаляйте старые, когда идете.

/** 
* Transfers and converts all entries from <code>map1</code> to 
* <code>map2</code>. Specifically, the {@link Foo} objects of the 
* inner maps will be converted to integer arrays via {@link Foo#toArray}. 
* 
* @param map1 Map to be emptied. 
* @param map2 Receptacle for the converted entries. 
*/ 
private static void transfer(Map<String, Map<Object, Foo>> map1 
     , Map<String, Map<Object, int[]>> map2) { 

    final Iterator<Entry<String, Map<Object, Foo>>> mapIt 
     = map1.entrySet().iterator(); 
    while (mapIt.hasNext()) { 
     final Entry<String, Map<Object, Foo>> mapEntry = mapIt.next(); 
     mapIt.remove(); 
     final Map<Object, int[]> submap = new HashMap<Object,int[]>(); 
     map2.put(mapEntry.getKey(), submap); 
     final Iterator<Entry<Object,Foo>> fooIt 
      = mapEntry.getValue().entrySet().iterator(); 
     while (fooIt.hasNext()) { 
      final Entry<Object,Foo> fooEntry = fooIt.next(); 
      fooIt.remove(); 
      submap.put(fooEntry.getKey(), fooEntry.getValue().toArray()); 
     } 
    } 
} 
4

у меня не было времени, чтобы проверить это, но я думаю, что-то, как это должно работать на SCALA Maps (если вы используете Scala 2.8, который, наконец, здесь):

mpO.mapValues(_.mapValues(_.toArray)) 

It возьмет вашу внешнюю карту и «заменит» все внутренние карты новым, где значения будут массивами Int. Ключи и общая «структура» карт остаются неизменными. Согласно scaladoc «Полученная карта обертывает исходную карту без копирования каких-либо элементов», поэтому она не будет реальной заменой.

Если вы также сделать

import scala.collection.JavaConversions._ 

то карты Java можно использовать точно так же, как карты SCALA: JavaConversions содержат кучу неявных методов, которые могут преобразовывать между SCALA и ява коллекций.

BTW с использованием карты < Строки, HashMap < Object, Array < Int >>> может быть не очень удобно в конце концов, если бы я тебя, я бы рассмотреть вопрос о введении некоторых классов, которые скрывают сложность этой конструкции.

Edit отражающее на ваш комментарий

import scala.collection.JavaConversions._ 
import java.util.Collections._ 

object MapValues { 
    def main(args: Array[String]) { 
    val jMap = singletonMap("a",singletonMap("b", 1)) 
    println(jMap) 
    println(jMap.mapValues(_.mapValues(_+1))) 
    } 
} 

принты:

{а = {Ь = 1}}
Map (а -> Карта (б -> 2))

Показано, что имплициты применяются как к внешней, так и к внутренней карте довольно хорошо.Это цель объекта JavaConversions: даже если у вас есть коллекция java, вы можете использовать ее как аналогичный класс scala (с расширенными функциями).
Вам не нужно ничего делать, просто импортировать JavaConversions._

+0

Спасибо, но, хотя я использую Scala для проекта, HashMaps являются Java HashMaps, так что вы не можете назвать mapVAlues на них. Есть ли способ решить эту проблему с помощью JavaConversions? – Skuge

+0

Вы смогли решить вашу проблему? Помогло ли мое редактирование? –

3

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

Почему вы не вызовите remove() метод итератора или set.remove (iterator.next()) где iterator.next() возвращает ключ, набор является набором ключей и итератора его итератор.

PS: Также попробуйте реорганизовать структуру данных, возможно, некоторые промежуточные классы, которые обрабатывают поиск данных? Карта на карте с массивами как значения ничего не говорит и ее сложно отслеживать.

3

Например, с использованием клавиш String; Назовём на вход данные: Map<String, Map<String, Object>> data

for (Entry<String, Map<String, Tuple>> entry : data.entrySet()) { 
    String itemKey = entry.getKey(); 
    for (Entry<String, Object> innerEntry : entry.getValue().entrySet()) { 
    String innerKey = innerEntry.getKey(); 
    Object o = innerEntry.getValue(); 
    // whatever, here you have itemKey, innerKey and o 
    } 
} 
Смежные вопросы