Наиболее эффективный способ преобразования / сглаживания всей карты в список (ключи и значения вместе, а не по отдельности) - PullRequest
5 голосов
/ 01 ноября 2019

Мне нужно преобразовать следующее:

Map<Long,Map<String,String>> mapOfMaps

в

List<List<String>> listOflists

, где ключи внешней карты (mapOfMaps) являются избыточными (для этой операции). В общем, я могу просто использовать mapOfMaps.values().stream() для начала.

И для каждого объекта карты, например:

{"apple": "1", "orange": "2 "}

Мне нужно преобразовать его в список:

{" apple "," 1 "," orange "," 2 "}

Какой самый эффективный способ сделать это?

Полный пример:

{"1L": {"key1": "value1", "key2":" value2 "}," 2L ": {" key3 ":" value3 "," key4 ":" value4 "}}

Ожидается:

[[ключ1, значение1, ключ2, значение2], [ключ3, значение3, ключ4, значение4]]

Ответы [ 4 ]

7 голосов
/ 01 ноября 2019

Примерно так:

List<List<String>> listOflists =
    mapOfMaps.values()
             .stream()
             .map(m -> m.entrySet()
                        .stream()
                        .flatMap(e->Stream.of(e.getKey(),e.getValue()))
                        .collect(Collectors.toList()))
             .collect(Collectors.toList());

Для каждого внутреннего Map вы создаете поток через entrySet() и создаете поток всех ключей и значений, которые вы собираете в List.

Например, если вы инициализируете Map с помощью:

Map<Long,Map<String,String>> mapOfMaps = new HashMap<>();
mapOfMaps.put(1L,new HashMap());
mapOfMaps.put(2L,new HashMap());
mapOfMaps.get(1L).put("key1","value1");
mapOfMaps.get(1L).put("key2","value2");
mapOfMaps.get(2L).put("key3","value3");
mapOfMaps.get(2L).put("key4","value4");

Вы получите следующее List:

[[key1, value1, key2, value2], [key3, value3, key4, value4]]
3 голосов
/ 01 ноября 2019

Ниже моя версия решения. Вы можете перебирать записи и соответственно добавлять значения в требуемый список.

        List<List<String>> list = map.
                values()
                .stream()
                .map(value -> {
                    List<String> list1 = new ArrayList<>();
                    for (Map.Entry<String, String> entry : value.entrySet()) {
                        list1.add(entry.getKey());
                        list1.add(entry.getValue());
                    }
                    return list1;
                })
                .collect(Collectors.toList());

Тестовый ввод:


        Map<Long, Map<String, String>> map = new HashMap<>();

        Map<String, String> submap1 = new HashMap<>();
        submap1.put("test", "test2");

        Map<String, String> submap2 = new HashMap<>();
        submap2.put("test6", "6");

        map.put(1l, submap1);
        map.put(2l, submap2);


1 голос
/ 11 ноября 2019

Если вы открыты для использования сторонней библиотеки, то с помощью Eclipse Collections :

@Test
public void mapOfMapsToListOfLists()
{
    MutableMap<Long, MutableSortedMap<String, String>> map = Maps.mutable.with(
            1L, SortedMaps.mutable.with("key1", "value1", "key2", "value2"),
            2L, SortedMaps.mutable.with("key3", "value3", "key4", "value4"));

    MutableList<MutableList<String>> listOfLists = map.valuesView()
            .collect(innerMap -> innerMap.keyValuesView()
                    .flatCollect(this::pairToList).toList())
            .toList();

    List<List<String>> expected = Lists.mutable.with(
            Lists.mutable.with("key1", "value1", "key2", "value2"),
            Lists.mutable.with("key3", "value3", "key4", "value4"));
    Assert.assertEquals(expected, listOfLists);
}

public ImmutableList<String> pairToList(Pair<String, String> pair)
{
    return Lists.immutable.with(pair.getOne(), pair.getTwo());
}

я инициализировал внутренние карты как SortedMap s, чтобы выполнить следующие действия:чтобы гарантировать порядок ключей при звонке на Assert.assertEquals в тесте. Типы интерфейсов, которые я использовал выше, взяты из коллекций Eclipse и расширяют типы интерфейсов JDK (например, MutableMap расширяет Map, MutableList расширяет список), но вы также можете использовать типы JDK со статической утилитой следующим образом:

@Test
public void jdkMapOfMapsToListOfLists()
{
    Map<Long, Map<String, String>> map = Maps.mutable.with(
            1L, SortedMaps.mutable.with("key1", "value1", "key2", "value2"),
            2L, SortedMaps.mutable.with("key3", "value3", "key4", "value4"));

    List<List<String>> listOfLists = MapIterate.collect(map,
            innerMap -> Iterate.flatCollect(
                    innerMap.entrySet(),
                    this::entryToList,
                    new ArrayList<>()));

    List<List<String>> expected = Arrays.asList(
            Arrays.asList("key1", "value1", "key2", "value2"),
            Arrays.asList("key3", "value3", "key4", "value4"));
    Assert.assertEquals(expected, listOfLists);
}

public List<String> entryToList(Map.Entry<String, String> entry)
{
    return Arrays.asList(entry.getKey(), entry.getValue());
}

Примечание: Я коммиттер Eclipse Collections

1 голос
/ 01 ноября 2019

Вот решение, которое немного менее круто, чем вложенные лямбды, но немного более читабельно:

public static void main(String[] args) {
    // create a result list
    List<List<String>> resultList = new ArrayList<>();

    // create some try-out values
    // a source map
    Map<Long,Map<String,String>> mapOfMaps = new HashMap<>();
    // some sub maps
    Map<String, String> subMapOne = new HashMap<>();
    subMapOne.put("One", "1");
    subMapOne.put("Two", "2");
    subMapOne.put("Three", "3");

    Map<String, String> subMapTwo = new HashMap<>();
    subMapTwo.put("Two", "2");

    Map<String, String> subMapThree = new HashMap<>();
    subMapThree.put("One", "1");
    subMapThree.put("Three", "3");

    mapOfMaps.put(1l, subMapOne);
    mapOfMaps.put(2l, subMapTwo);
    mapOfMaps.put(3L, subMapThree);

    // just nest two forEach-calls
    mapOfMaps.forEach((key, value) -> {
        // create a new list for each submap
        List<String> subList = new ArrayList<>();
        value.forEach((subKey, subValue) -> {
            // and add each entry of the submap to it
            subList.add(subKey);
            subList.add(subValue);
        });
        // finally add the list to the result list
        resultList.add(subList);
    });

    resultList.forEach(System.out::println);
}

Вывод

[One, 1, Two, 2, Three, 3]
[Two, 2]
[One, 1, Three, 3]
...