这个问题似乎相当复杂,所以我在这里发布这个问题,寻找任何可能的解决方法。
我有地图清单。我想要一个地图列表,但要确保地图被转换成某种层次结构。
原始数据:(列表
[
{
"studentId": 101,
"name": "John",
"subjectId": 2001,
"marks": 85,
"street": "Bakers Street",
"state": "LA"
},
{
"studentId": 101,
"name": "John",
"subjectId": 2002,
"marks": 75,
"street": "Bakers Street",
"state": "LA"
},
{
"studentId": 102,
"name": "Shae",
"subjectId": 3001,
"marks": 96,
"street": "Howards",
"state": "NYC"
}
]
此地图列表将转换为以下地图列表:(列表)
[
{
"studentId": 101,
"name": "John",
"academics":
[
{
"subjectId": 2001,
"marks": 85
},
{
"subjectId": 2002,
"marks": 75
}
],
"address":
{
"street": "Bakers Street",
"state": "LA"
}
},
{
"studentId": 102,
"name": "Shae",
"academics":
[
{
"subjectId": 3001,
"marks": 96
}
],
"address":
{
"street": "Howards",
"state": "NYC"
}
}
]
作为一个简单的解决方案,我试图手动处理它们(真的很无聊),所以我在寻找使用流或任何其他可能的方式来处理它们的任何高效、干净的方法。
更新朴素的解决方案如下
public List<Map<String, Object>> transformResultSet(List<Map<String, Object>> flatDataList) {
List<Map<String, Object>> hierarchicalDataList = new ArrayList<Map<String, Object>>();
Map<String, List<Map<String, Object>>> studentIdToStudentDataListMap = new LinkedHashMap<>();
for (Map<Integer, Object> flatData : flatDataList) {
if (studentIdToStudentDataListMap.get(flatData.get("student_id")) == null) {
studentIdToStudentDataListMap.put(Integer.valueOf(flatData.get("student_id").toString()), new ArrayList<Map<String, Object>>());
}
studentIdToStudentDataListMap.get(Integer.valueOf(flatData.get("student_id").toString())).add(flatData);
}
for (Map.Entry<Integer, List<Map<String, Object>>> studentFlatDataList : studentIdToStudentDataListMap.entrySet()) {
Map<String, Object> studentHierarchicalDataMap = new LinkedHashMap<String, Object>();
Map<String, Object> studentFlatDataMap = studentFlatDataList.getValue().get(0);
studentHierarchicalDataMap.put("studentId", studentFlatDataMap.get("studentId"));
studentHierarchicalDataMap.put("name", studentFlatDataMap.get("name"));
List<Map<String, Object>> academicsList = new ArrayList<Map<String, Object>>();
for (Map<String, Object> studentDetailAcademic : studentFlatDataList.getValue()) {
Map<String, Object> academic = new LinkedHashMap<String, Object>();
academic.put("subjectId", studentDetailAcademic.get("subjectId"));
academic.put("marks", studentDetailAcademic.get("marks"));
academicsList.add(academic);
}
studentHierarchicalDataMap.put("academics", academicsList);
Map<String, Object> address = new LinkedHashMap<String, Object>();
address.put("street", studentFlatDataMap.get("street"));
address.put("state", studentFlatDataMap.get("state"));
studentHierarchicalDataMap.put("address", address);
hierarchicalDataList.add(studentHierarchicalDataMap);
}
return hierarchicalDataList;
}
似乎您需要按学生分组,同时还要更改json结构。
在更高的层次上,您可以这样做(稍后我们将看到详细信息):
Map<Integer, Map<String, Object>> grouped = flatDataList.stream()
.collect(Collectors.toMap(
s -> (Integer) s.get("studentId"),
s -> transformToHierarchicalStudent(s),
(oldS, newS) -> mergeHierarchicalStudents(oldS, newS)));
因此,这将创建一个分层格式的学生地图,按studentId
分组。我们授权给两种方法:一种是从一个普通学生中创建一个分层学生,另一种是合并两个具有相同studentId
的分层学生。
transformToHi分层学生
方法如下:
Map<String, Object> transformToHierarchicalStudent(Map<String, Object> flat) {
Map<String, Object> student = new LinkedHashMap<>();
student.put("studentId", flat.get("studentId"));
student.put("name", flat.get("name"));
Map<String, Object> address = new LinkedHashMap<>();
address.put("street", flat.get("street"));
address.put("state", flat.get("state"));
student.put("address", address);
List<Map<String, Object>> academics = new ArrayList<>();
Map<String, Object> subject = new LinkedHashMap<>();
subject.put("subjectId", flat.get("subjectId"));
subject.put("marks", flat.get("marks"));
academics.add(subject);
student.put("academics", academics);
return student;
}
以及mergeHierarchicalStudents
方法:
Map<String, Object> mergeHierarchicalStudents(
Map<String, Object> oldSt, Map<String, Object> newSt) {
// We only need to merge the subjects
List<Map<String, Object>> oldAcademics =
(List<Map<String, Object>>) oldSt.get("academics");
List<Map<String, Object>> newAcademics =
(List<Map<String, Object>>) newSt.get("academics");
oldAcademcis.addAll(newAcademics);
return oldS;
}
这假设在原始平面列表中没有相同学生的重复科目。
最后,如果需要分层学生的列表
,只需获取地图值:
List<Map<String, Object>> hierarchicalStudents = new ArrayList<>(grouped.values());
您可以将算法分为几个步骤:
subject
,标记
到新的地图
步骤1
和
2
都是相同的。我们可以将其提取到一个新类中,以避免重复方法引用:
class ExtractKeysToMap implements Function<Map<String, Object>, Map<String, Object>> {
private final List<String> keys;
private final String newKey;
ExtractKeysToMap(String newKey, List<String> keys) {
this.newKey = Objects.requireNonNull(newKey);
this.keys = Objects.requireNonNull(keys);
}
@Override
public Map<String, Object> apply(Map<String, Object> map) {
Map<String, Object> academics = new HashMap<>();
keys.forEach(key -> {
Object value = map.remove(key);
if (value != null) academics.put(key, value);
});
map.put(newKey, academics);
return map;
}
}
由于我们已经实现了第一步和第二步,我们可以在下面的示例中使用它:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.CollectionType;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./src/main/resources/test.json");
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
CollectionType jsonType = mapper.getTypeFactory().constructCollectionType(List.class, Map.class);
List<Map<String, Object>> response = mapper.readValue(jsonFile, jsonType);
final String academicsKey = "academics";
Collection<Map<String, Object>> result = response
.stream()
.map(new ExtractKeysToMap(academicsKey, Arrays.asList("subjectId", "marks")))
.map(new ExtractKeysToMap("address", Arrays.asList("street", "state")))
.peek(map -> map.computeIfPresent(academicsKey, (k, v) -> new LinkedList<>(Collections.singletonList(v))))
.collect(Collectors.toMap(
map -> map.get("studentId"),
map -> map,
(map0, map1) -> {
((List<Object>) map0.get(academicsKey)).addAll((List<Object>) map1.get(academicsKey));
return map0;
}))
.values();
mapper.writeValue(System.out, result);
}
}
以上代码打印:
[ {
"studentId" : 101,
"name" : "John",
"academics" : [ {
"subjectId" : 2001,
"marks" : 85
}, {
"subjectId" : 2002,
"marks" : 75
} ],
"address" : {
"street" : "Bakers Street",
"state" : "LA"
}
}, {
"studentId" : 102,
"name" : "Shae",
"academics" : [ {
"subjectId" : 3001,
"marks" : 96
} ],
"address" : {
"street" : "Howards",
"state" : "NYC"
}
} ]
从您的json示例中,您似乎有List
假设输入对象是
Student
和StudentDto
具有列表
Map<String, List<Student>> map = list.stream().collect(groupingBy(Student::studentId));
Map<String, StudentDto> dtoMap = new HashMap<>();
for(Map.Entry<String, List<Student>> entry : map.entrySet()) {
StudentDto stud = new StudentDto();
//assign other studentDto properties
for(Student std : entry.getValue()) {
MarkDto mark = new MarkDto();
mark.setSubjectId(std.getStudentid());
mark.setMark(entry.getMark()));
stud.add(mark);
}
dtoMap.put(String.valueOf(stud.getId()), stud);
}
return dtoMap.stream().collect(Collectors.toList()); // or return the map itself
问题内容: 我有一个下面的层次结构,我想将其转换为平面。 我已经写了一种方法并使用了它。但是最终结果中缺少一些要素。我做错什么了? 还有比我以前将列表转换为平面列表更好的方法吗? 我添加了一个示例代码和类似于我在场景中必须使用的对象的内容。最终结果应为1、2、3、4、5、6、7 问题答案: 如果a 有子项,则可以正确地将子项添加到拼合列表中,但是会错过其本身。只需将成员的添加移动到块添加之外,就可
问题内容: 我有对象T的列表,它具有父属性,其中顶级对象的父属性为null。我想将所有对象放入TreeSet(或TreeMap)中。顶级对象将是所有没有父级的根对象(父级为null),并且它们的下级将是其子级。 像这样 所以我可以得到Ra并找到它的子代(Ca1,Ca2,Ca11,Ca12…。) 更新:很抱歉,可能不清楚,节点指向父节点,如果parent为null,则它们是根节点。问题是父母需要了解
问题内容: 我有一个带有字段的“页面”对象列表。此父字段引用列表中的另一个对象。我想基于此字段从此列表创建树层次结构。 这是我原始列表的样子: 我想将其转换为这样的树结构: 我希望可以在任何时候针对任意列表调用的可重用函数。有人知道解决这个问题的好方法吗?任何帮助或建议,将不胜感激! 问题答案: 小提琴
我正在使用www.modelmapper。org和我正致力于将相同的“平面”JavaDTO映射到几个“层次”DTO 平面DTO有许多基本属性 层次结构有许多复杂类型,其中包含许多基本类型。这些DTO非常相似,但并不相同 “扁平”DTO: “分层DTO: TransactionRequest应映射为1)PurchaseRequest和2)CancelRequest 问题之一是,金额必须从Long(小
问题内容: 我有一个列表列表: 我想将其平均 我的代码好像不太优雅。这是遍历列表的幼稚方法,将总和保存在单独的容器中,然后除以元素数。 我认为有一种Python方式可以做到这一点。有什么建议?谢谢 问题答案: 纯Python: 印刷 NumPy: Python 3:
我有一个带有< code>parent字段的“page”对象列表。该父字段引用了列表中的另一个对象。我想从基于此字段的列表中创建一个树层次结构。 以下是我的原始列表: 我想把它转换成这样的树形结构: 我希望有一个可重用的函数,我可以随时对任意列表调用它。有谁知道处理这个问题的好方法吗?任何帮助或建议将不胜感激!