[英]How to transform a Map<String, List<String>> into a List<Map<String, String>> and get Cartesian product?
使用 Java 我试图创建 map 的笛卡尔积,其中包含String
键和List<String>
值。 创建列表时,我需要保留键的值,如下所示:
Map<String, List<String>>
ObjectList<Map<String, String>>
Object 我还要求当原始 map 中的List<String>
值为空时,在创建笛卡尔积时仍应将其视为单个值,以避免乘以 0 和不创建映射。 例如下面的 map:
{
"Location Number" = {"100", "500"}
"Department Number" = {"11", "22", "33"}
"District Number" = {}
"Preferred Language" = {"en-US"}
}
被翻译成:
{
{
"Location Number" = "100"
"Department Number" = "11"
"District Number" = {}
"Preferred Language" = "en-US"
},
{
"Location Number" = "100"
"Department Number" = "22"
"District Number" = {}
"Preferred Language" = "en-US"
},
{
"Location Number" = "100"
"Department Number" = "33"
"District Number" = {}
"Preferred Language" = "en-US"
},
{
"Location Number" = "500"
"Department Number" = "11"
"District Number" = {}
"Preferred Language" = "en-US"
},
{
"Location Number" = "500"
"Department Number" = "22"
"District Number" = {}
"Preferred Language" = "en-US"
},
{
"Location Number" = "500"
"Department Number" = "33"
"District Number" = {}
"Preferred Language" = "en-US"
}
}
下面是我目前用来完成类似翻译的代码,但它没有保留我需要的密钥。 我不知道一般使用 Java 8 Streams 是否有可能完成此操作。
private static List<List<String>> createRuleListFromMap(Map<String, List<String>> ruleMap) {
List<List<String>> ruleList = new ArrayList<>();
cartesianProduct(ruleMap.values()).forEach(ruleList::add);
return ruleList;
}
private static <T> Stream<List<T>> cartesianProduct(Collection<? extends Collection<T>> collections) {
return cartesianProduct(new ArrayList<Collection<T>>(collections), Collections.emptyList());
}
private static <T> Stream<List<T>> cartesianProduct(List<? extends Collection<T>> collections, List<T> current) {
return collections.isEmpty() ? Stream.of(current) : collections.get(0).stream().flatMap(e -> {
List<T> list = new ArrayList<>(current);
list.add(e);
return cartesianProduct(collections.subList(1, collections.size()), list);
});
}
下面是如何将Map<String,List<String>>
转换为List<Map<String,String>>
的简单示例:
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class StreamTest {
@Test
public void test() {
var map = new HashMap<String, List<String>>();
map.put("key1", Arrays.asList("value1", "value2", "value3"));
map.put("key2", Arrays.asList("value4", "value5", "value6"));
var list = map.entrySet().stream()
.flatMap(e -> e.getValue().stream()
.map(v -> Map.of(e.getKey(), v)))
.collect(Collectors.toList());
log.info(list.toString());
}
}
您可以首先将列表的元素表示为Map<String,String>
,并获得stream 的地图列表,然后通过顺序求和内部地图对以获得笛卡尔积,将此 stream reduce
为单个列表。
Map<String, List<String>> map = new LinkedHashMap<>();
map.put("Location Number", List.of("100", "500"));
map.put("Department Number", List.of("11", "22", "33"));
map.put("District Number", List.of("")); // NOT an empty list!
map.put("Preferred Language", List.of("en-US"));
List<Map<String, String>> list = map.entrySet().stream()
.map(entry -> entry.getValue().stream()
// list elements as Map<String,String>
.map(str -> Map.of(entry.getKey(), str))
// List<Map<String,String>>
.collect(Collectors.toList()))
// intermediate output
.peek(System.out::println)
// stream of lists to a single list
.reduce((list1, list2) -> list1.stream()
// combinations of inner maps
.flatMap(map1 -> list2.stream()
// join entries of two maps
.map(map2 -> {
Map<String, String> mp =
new LinkedHashMap<>();
mp.putAll(map1);
mp.putAll(map2);
return mp;
}))
// list of combinations
.collect(Collectors.toList()))
// returns List<Map<String,String>
// otherwise an empty list
.orElse(Collections.emptyList());
// final output
list.forEach(System.out::println);
中级output:
[{Location Number=100}, {Location Number=500}]
[{Department Number=11}, {Department Number=22}, {Department Number=33}]
[{District Number=}]
[{Preferred Language=en-US}]
最终 output:
{Location Number=100, Department Number=11, District Number=, Preferred Language=en-US}
{Location Number=100, Department Number=22, District Number=, Preferred Language=en-US}
{Location Number=100, Department Number=33, District Number=, Preferred Language=en-US}
{Location Number=500, Department Number=11, District Number=, Preferred Language=en-US}
{Location Number=500, Department Number=22, District Number=, Preferred Language=en-US}
{Location Number=500, Department Number=33, District Number=, Preferred Language=en-US}
另请参阅:将 map 列表转换为地图列表
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.