简体   繁体   English

如何改造一个Map <string, list<string> > 进入列表<map<string, string> > 得到笛卡尔积? </map<string,></string,>

[英]How to transform a Map<String, List<String>> into a List<Map<String, String>> and get Cartesian product?

Using Java I am attempting to create the Cartesian Product of a map which contains String keys and List<String> values.使用 Java 我试图创建 map 的笛卡尔积,其中包含String键和List<String>值。 I need to preserve the values of the keys when creating the list like so:创建列表时,我需要保留键的值,如下所示:

  • From a Map<String, List<String>> Object来自Map<String, List<String>> Object
  • To a List<Map<String, String>> ObjectList<Map<String, String>> Object

I also have the requirement that when a List<String> value in the original map is empty it should still be treated as a single value when creating the Cartesian Product so as to avoid multiplying by 0 and creating no maps.我还要求当原始 map 中的List<String>值为空时,在创建笛卡尔积时仍应将其视为单个值,以避免乘以 0 和不创建映射。 For example the following map:例如下面的 map:

{
    "Location Number" = {"100", "500"}
    "Department Number" = {"11", "22", "33"}
    "District Number" = {}
    "Preferred Language" = {"en-US"}
}

Is translated to:被翻译成:

{
    {
        "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"
    }
}

Below is the code I am currently using to accomplish a similar translation, but it does not retain the key, which I need.下面是我目前用来完成类似翻译的代码,但它没有保留我需要的密钥。 I do not know if this is possible to accomplish using Java 8 Streams in general.我不知道一般使用 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);
    });
}

Here is simple example how to transform Map<String,List<String>> to List<Map<String,String>> :下面是如何将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());
    }
}

You can first represent the elements of lists, each as Map<String,String> , and get a stream of lists of maps , and then reduce this stream to a single list by sequentially summing pairs of inner maps to get the Cartesian product .您可以首先将列表的元素表示为Map<String,String> ,并获得stream 的地图列表,然后通过顺序求和内部地图对以获得笛卡尔积,将此 stream reduce为单个列表

Try it online! 在线试用!

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);

Intermediate output:中级output:

[{Location Number=100}, {Location Number=500}]
[{Department Number=11}, {Department Number=22}, {Department Number=33}]
[{District Number=}]
[{Preferred Language=en-US}]

Final output:最终 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}

See also: Convert a map of lists into a list of maps另请参阅:将 map 列表转换为地图列表

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从字符串集映射中获取笛卡尔积 - How to get cartesian product from Map of String Set 结果集列表 <Product> 和清单 <Map<String, String> &gt; - ResultSet to List<Product> and List<Map<String, String>> 如何转换列表<String>到地图<String,String>使用 Google 收藏? - How to transform List<String> to Map<String,String> with Google collections? 如何转换地图 <String,String> 列表 <String> 使用谷歌收藏 - how to transform Map<String,String> to List<String> using google collections 使用Java 8流,如何转换Map <String, Map<String, List<Person> &gt;&gt;到地图 <Integer, Map<String, Integer> &gt;? - Using Java 8 streams, how to transform Map<String, Map<String, List<Person>>> to Map<Integer, Map<String, Integer>>? 如何转换地图 <String, List<String> &gt;按键值放入文件 - How to transform Map<String, List<String>> into Files by Key Value 如何映射地图 <String, List<String> &gt;在休眠状态 - How to map Map<String, List<String>> in hibernate 如何转换地图 <String, List<String> &gt;到地图 <String, String> 在java 8中 - How to Convert a Map<String, List<String>> to Map<String, String> in java 8 如何转换列表<map<string, object> > 列出<map<string, string> > </map<string,></map<string,> - How to Convert List<Map<String, Object>> to List<Map<String, String>> 获取 Map 中最内层的值作为 `Map 中的列表<string, list<map<string,map<string,string> &gt;&gt;&gt;` Java</string,> - Get inner most values in the Map as a List in `Map<String, List<Map<String,Map<String,String>>>>` Java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM