Как превратить String[][] в Map<String, Map<Integer, List<String[]>>>

166
01 сентября 2021, 22:30

интересует красивый способ преобразования двумерного массива строк в мапу, значениями которой будет мапа, значениями которой будет список массивов строк %)

Например, исходный двумерный массив строк:

_values = new String[][] 
{
    new String[] {"Mars", "1991", "1", "item1"}, 
    new String[] {"Mars", "1991", "2", "item2"},
    new String[] {"Mars", "1991", "3", "item3"},
    new String[] {"Venus", "1992", "11", "item11"},
    new String[] {"Venus", "1992", "22", "item22"},
    new String[] {"Venus", "1993", "33", "item33"}
};

Нужно, чтобы результат имел тип:

Map<String, Map<Integer, List<String[]>>> result;

И обращаться к нему можно было бы так:

List<String[]> listMars1991 = result.get("Mars").get(1991);
listMars1991.get(0) // {"Mars", "1991", "1", "item1"}
listMars1991.get(1) // {"Mars", "1991", "2", "item2"}
listMars1991.get(2) // {"Mars", "1991", "3", "item3"}
List<String[]> listVenus1992 = result.get("Venus").get(1992);
listVenus1992.get(0) // {"Venus", "1992", "11", "item11"}
listVenus1992.get(1) // {"Venus", "1992", "22", "item22"}
List<String[]> listVenus1993 = result.get("Venus").get(1993);
listVenus1993.get(0) // {"Venus", "1993", "33", "item33"}

Вот существующее решение. Но оно не кажется мне красивым.

private Map<String, Map<Integer, List<String[]>>> getMappedPlanets(String[][] values)
{
    Map<String, Map<Integer, List<String[]>>> retVal = new HashMap<>(); 
    Map<String, List<String[]>> byPlanetMap = new HashMap<>();
    for (String[] value : values)
    {
        String planetName = value[0];
        List<String[]> items = new ArrayList<>();
        items.add(value);
        byPlanetMap.merge(planetName, items, (oldVal, newVal) -> 
        {
            oldVal.addAll(items);
            return oldVal;
        }); 
    }       
    byPlanetMap.forEach((planetName, items) -> 
    {
        Map<Integer, List<String[]>> byYearMap = new HashMap<>();
        items.forEach(item -> 
        {
            Integer year = Integer.parseInt(item[1]);               
            List<String[]> byYearList = new ArrayList<>();
            byYearList.add(item);
            byYearMap.merge(year, byYearList, (oldVal, newVal) -> 
            {
                oldVal.addAll(byYearList);
                return oldVal;
            });             
        });
        retVal.put(planetName, byYearMap);              
    });
    return retVal;
}
Answer 1

https://www.baeldung.com/java-groupingby-collector

Map<String, Map<Integer, List<String[]>>> result =
        Arrays.stream(_values).collect(
                Collectors.groupingBy(e -> e[0],
                        Collectors.groupingBy(e -> Integer.valueOf(e[1]))));
Answer 2
Map<String, Map<Integer, List<String[]>>> result =
        Arrays.stream(_values).collect(
              Collectors.groupingBy(a -> a[0],
                    Collectors.groupingBy(v -> Integer.valueOf(v[1]),
                          Collectors.mapping(v -> v, Collectors.toList()))));
Answer 3
public static void main(String[] args) {
    Map<String, Map<Integer, List<String[]>>> result = new HashMap<>();
    String[][] _values = new String[][]{
            new String[]{"Mars", "1991", "1", "item1"},
            new String[]{"Mars", "1991", "2", "item2"},
            new String[]{"Mars", "1991", "3", "item3"},
            new String[]{"Venus", "1992", "11", "item11"},
            new String[]{"Venus", "1992", "22", "item22"},
            new String[]{"Venus", "1993", "33", "item33"}
    };
    List<String[]> list = new ArrayList<>();
    for (int i = 0; i < _values.length; i++) {
        list.add((String[]) Array.get(_values, i));
    }
    List<String[]> marsList = new ArrayList<>();
    List<String[]> venusList = new ArrayList<>();
    for (String[] strings : list) {
        if (Arrays.toString(strings).contains("Mars")) {
            marsList.add(strings);
        } else if (Arrays.toString(strings).contains("Venus")) {
            venusList.add(strings);
        }
    }
    createMap(marsList, result, "Mars");
    createMap(venusList, result, "Venus");
    List<String[]> listMars1991 = result.get("Mars").get(1991);
    System.out.println(Arrays.toString(listMars1991.get(0)));
    System.out.println(Arrays.toString(listMars1991.get(1)));
    System.out.println(Arrays.toString(listMars1991.get(2)));
}
private static void createMap(Map<String, Map<Integer, List<String[]>>> result,
                              List<String[]> venusList, String name) {
    Map<Integer, List<String[]>> map = new HashMap<>();
    for (String[] strings : venusList) {
        map.put(Integer.parseInt((String) Array.get(strings, 1)), venusList);
    }
    result.put(name, map);
}

Можно как-то так. Над кодом ещё поработать надо, но главное понять можно.

READ ALSO
Почему здесь прибавляют 1?

Почему здесь прибавляют 1?

Добрый день не могу разобраться с кодом почему к переменной in добавляют 1

89
Не могу присвоить в переменную значение &quot;+&quot;, считанное Scannerом

Не могу присвоить в переменную значение "+", считанное Scannerом

Программа - калькуляторВвожу в консоли в строку значения, сканер их считывает

188
динамическое добавление input с уникальным id

динамическое добавление input с уникальным id

Передо мной стоит задача по нажатию добавлять input с кнопкой удаления этого инпутаМаксимальное кол-во инпутов 4

256