假设我有这样的多地图:
MiddleName -> null
EmailAddress -> Toni@mymail.com, Mary@hermail.com, Paul@hismail.com
FirstName -> Toni, Mary, Paul
LastName -> Barry, null ,White
Id -> null
注意每个“values”条目如何可以完全为null或包含与具有更多条目(我不知道哪个条目)的值相同的值,即使某些条目为空。
我希望它将它“转置”到这样的地图列表中:
MiddleName -> null
EmailAddress -> Toni@mymail.com
FirstName -> Toni
LastName -> Barry
Id -> null
MiddleName -> null
EmailAddress -> Mary@hermail
FirstName -> John
LastName -> null
Id -> null
MiddleName -> null
EmailAddress -> Paul@hismail.com
FirstName -> Paul
LastName -> White
Id -> null
我正在尝试使用java8流,但也可以使用“旧”样式。
搜索stackoverflow我发现了一个类似的问题[1],还有一些相关的问题[2,3,4]给了我一些想法,但并没有完全适应。
现在,我确实实现了我自己想要的解决方案,但坦率地说,这可能是我多年来写的最丑陋的代码......
List result = (...)
map.forEach(h -> {
MultiValueMap<String, String> m = new LinkedMultiValueMap();
h.entrySet().stream().forEach(e -> {
String[] ss = e.getValue() == null ? null : e.getValue().toString().split(",");
if (ss != null) {
Arrays.asList(ss).stream().forEach(s -> m.add(e.getKey(), s));
}
});
if (m.size() > 0) {
int x = m.values().stream().max((o1, o2) -> o1.size() - o2.size()).get().size();
for (int i = 0; i < x; i++) {
Map<String, String> n = (Map) h.clone();
Iterator<Map.Entry<String, String>> it = n.entrySet().iterator();
while( it.hasNext()){
Map.Entry<String, String> e = it.next();
List<String> ss = m.get(e.getKey());
if(ss!=null) {
e.setValue(ss.get(i));
}
}
result.add(n);
}
}
});
第一遍只是将字符串拆分成一个数组,因为它最初是一个逗号分隔的字符串。然后我找到任何值中的最大元素数量,我将条目中的所有值循环该次数,并为结果创建每个值的映射。坦率地说,我上周五写了这段代码,我还不能正确地阅读它......
所以,这首先是一个简单的事情,我最终得到了这个烂摊子,还有更好的方法吗?
提前致谢。
[1] Java8 streams : Transpose map with values as list
[2] reversing keys/values - create new instance of HashMap
[3] "Transpose" a hashmap for key->value to value->key?
[4] Java invert map
答案 0 :(得分:0)
我坦率地试图避免首先处于这种情况,并开始使用真实对象而不是地图(即使你想要的地图列表应该是List<Person>
),但我会这样做这样:
Map<String, List<String>> multiMap = ...;
List<Map<String, String>> result = new ArrayList<>();
// find an entry with a non-null value, and get the size of the
// list
OptionalInt sizeOfLists =
multiMap.values()
.stream()
.filter(Objects::nonNull)
.mapToInt(List::size)
.findAny();
// for each index, create a person and put each key and the
// corresponding value at that index in that map
sizeOfLists.ifPresent(size -> {
for (int i = 0; i < size; i++) {
int index = i;
Map<String, String> person = new HashMap<>();
result.add(person);
multiMap.entrySet()
.stream()
.filter(entry -> entry.getValue() != null)
.forEach(entry -> person.put(entry.getKey(), entry.getValue().get(index)));
}
});
请注意,您的代码并不是那么糟糕。但如果您为变量指定了有意义的名称而不是h
,m
,e
,ss
,那么它将更具可读性。
答案 1 :(得分:0)
这个怎么样(如果我理解正确的话):
BAPI_SFLIGHT_GETLIST
*"*"Lokale Schnittstelle:
*" IMPORTING
*" VALUE(FROMCOUNTRYKEY) LIKE BAPISFDETA-COUNTRYFR
*" VALUE(FROMCITY) LIKE BAPISFDETA-CITYFROM
*" VALUE(TOCOUNTRYKEY) LIKE BAPISFDETA-COUNTRYTO
*" VALUE(TOCITY) LIKE BAPISFDETA-CITYTO
*" VALUE(AIRLINECARRIER) LIKE BAPISFDETA-CARRID DEFAULT SPACE
*" VALUE(AFTERNOON) LIKE BAPI_AUX-AFTERNOON DEFAULT SPACE
*" VALUE(MAXREAD) LIKE BAPI_AUX-MAXREAD DEFAULT 0
*" EXPORTING
*" VALUE(RETURN) LIKE BAPIRET2 STRUCTURE BAPIRET2
*" TABLES
*" FLIGHTLIST STRUCTURE BAPISFLIST
从这里映射到某些Person对象相当容易。