#java #hashmap #tuples
#java #hashmap #кортежи
Вопрос:
Я хочу преобразовать javax.persistence.Tuple
в HashMap
, но вот так, он вставляет последний элемент кортежа и принимает также псевдоним и тип данных. Как я могу улучшить этот метод, чтобы он принимал значения кортежа?
public Map<String, Object> tuplesToMap(List<Tuple> data){
Map<String, Object> values = new HashMap<>();
data.forEach(tuple -> {
tuple.getElements().forEach(
element -> {
values.put(element.getAlias(), tuple.get(element));
}
);
});
return values;
}
Комментарии:
1. вы говорите о javax.persistence. Кортеж, не так ли?
2. @luca.vercelli да
Ответ №1:
с Java 8 просто :
return data.stream()
.collect(Collectors.toMap(
t -> t.get(0, String.class),
t -> t.get(1, Object.class)));
Ответ №2:
Кажется, работает :
public static List<Map<String/*UPPERCASE*/, Object>> jpaTuplesToMaps(
List<javax.persistence.Tuple> data
){
return data.stream()
.map(tuple -> { // per each tuple of the input List
// creating a new HashMap
Map<String, Object> resultItem = new HashMap<>();
// filling the created HashMap with values of
tuple.getElements().forEach( // each column of the tuple
col -> { resultItem.put(col.getAlias(), tuple.get(col)); }
);
// returning the created HashMap instead of the current Tuple
return resultItem;
})
// collecting amp; returning all the created HashMap-s as a List
.collect(Collectors.toList());
}
Но обычно требуются преобразования как отдельных элементов, так и списка, поэтому давайте объединим их :
public static Map<String/*UPPERCASE*/, Object> jpaTupleToMap(
javax.persistence.Tuple data /*CASE INSENSITIVE*/
){
Map<String, Object> result =
new HashMap<>(); // exactly HashMap since it can handle NULL keys amp; values
data.getElements().forEach(
col -> { result.put(col.getAlias(), data.get(col)); }
);
return resu<
}
//-------------------------
public static List<Map<String/*UPPERCASE*/, Object>> jpaTuplesToMaps(
List<javax.persistence.Tuple> data /*CASE INSENSITIVE*/
){
return data.stream() // List<Tuple> -> Tuple1,..TupleN
.map(tuple -> jpaTupleToMap(tuple)) // Tuple1 -> HashMap1,..TupleN -> HashMapN
.collect(Collectors.toList()); // HashMap1,..HashMapN -> List
}
Ответ №3:
element.getAlias()
Вы используете в качестве ключа для hashmap, вероятно, то же самое для некоторых элементов.
Map
ключи уникальны, что означает, что если вы вставляете записи (1, «один»), а затем (1, «два»), первое значение будет переопределено последним. Если вы хотите, чтобы несколько значений были сопоставлены одному ключу, используйте Map<String, Collection<Object>>
или Multimap
из Guava, что в точности одно и то же.
Вы можете вставить в multimap с помощью этой функции — если ключа нет в карте, создайте новый ArrayList
и добавьте его на карту, в противном случае верните существующий. Затем вставьте значение в список:
values
.computeIfAbsent(element.getAlias, k -> new ArrayList<>())
.add(tuple.get(element));
Комментарии:
1. Если я сделаю это таким образом, я получу несовместимый тип для tuple.get (element)
2. Да, вам также необходимо создать коллекцию, в которую вы поместили элементы — вы изменили значения в карте с
Object
наCollection<Object>
3. Вы, конечно, можете это сделать, в этом случае у вас было бы
List<Map<String, Object>>
вместоMap<String, List<Object>>
— просто имейте в виду, что ключи карты уникальны, и вам решать, не перезаписывать ли существующее отображение.4. Я согласен с @OndraK. Я просто понимаю, что
List<Tuple>
на самом деле является матрицей или также таблицей. Поэтому нецелесообразно преобразовывать его вMap<String, Object>
, который представляет собой одну строку таблицы. Разумнее преобразовать его вList<Map<String, Object>>
.