将List <Map <String,List <String >>>转换为String [] []

MartynasJusevičius:

我有一个用例,其中我会刮一些数据,对于某些记录,某些键具有多个值。我想要的最终输出是CSV,我有一个库,它需要一个二维数组。

因此,我的输入结构看起来像List<TreeMap<String, List<String>>>(我TreeMap用来确保稳定的键顺序),而我的输出则需要是String[][]

我编写了一个通用转换,该转换基于所有记录中值的最大数目来计算每个键的列数,并为具有小于最大值的记录留空单元格,但结果却比预期的要复杂。

我的问题是:它可以更简洁/有效(但仍然通用)的方式编写吗?特别是使用Java 8流/ lambdas等吗?

样本数据和我的算法如下(尚未经过样本数据测试):

package org.example.import;

import java.util.*;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {
        List<TreeMap<String, List<String>>> rows = new ArrayList<>();
        TreeMap<String, List<String>> row1 = new TreeMap<>();
        row1.put("Title", Arrays.asList("Product 1"));
        row1.put("Category", Arrays.asList("Wireless", "Sensor"));
        row1.put("Price",Arrays.asList("20"));
        rows.add(row1);
        TreeMap<String, List<String>> row2 = new TreeMap<>();
        row2.put("Title", Arrays.asList("Product 2"));
        row2.put("Category", Arrays.asList("Sensor"));
        row2.put("Price",Arrays.asList("35"));
        rows.add(row2);
        TreeMap<String, List<String>> row3 = new TreeMap<>();
        row3.put("Title", Arrays.asList("Product 3"));
        row3.put("Price",Arrays.asList("15"));
        rows.add(row3);

        System.out.println("Input:");
        System.out.println(rows);
        System.out.println("Output:");
        System.out.println(Arrays.deepToString(multiValueListsToArray(rows)));
    }

    public static String[][] multiValueListsToArray(List<TreeMap<String, List<String>>> rows)
    {
        Map<String, IntSummaryStatistics> colWidths = rows.
                stream().
                flatMap(m -> m.entrySet().stream()).
                collect(Collectors.groupingBy(e -> e.getKey(), Collectors.summarizingInt(e -> e.getValue().size())));
        Long tableWidth = colWidths.values().stream().mapToLong(IntSummaryStatistics::getMax).sum();
        String[][] array = new String[rows.size()][tableWidth.intValue()];
        Iterator<TreeMap<String, List<String>>> rowIt = rows.iterator(); // iterate rows
        int rowIdx = 0;
        while (rowIt.hasNext())
        {
            TreeMap<String, List<String>> row = rowIt.next();
            Iterator<String> colIt = colWidths.keySet().iterator(); // iterate columns
            int cellIdx = 0;
            while (colIt.hasNext())
            {
                String col = colIt.next();
                long colWidth = colWidths.get(col).getMax();
                for (int i = 0; i < colWidth; i++) // iterate cells within column
                    if (row.containsKey(col) && row.get(col).size() > i)
                        array[rowIdx][cellIdx + i] = row.get(col).get(i);
                cellIdx += colWidth;
            }
            rowIdx++;
        }
        return array;
    }

}

程序输出:

Input:
[{Category=[Wireless, Sensor], Price=[20], Title=[Product 1]}, {Category=[Sensor], Price=[35], Title=[Product 2]}, {Price=[15], Title=[Product 3]}]
Output:
[[Wireless, Sensor, 20, Product 1], [Sensor, null, 35, Product 2], [null, null, 15, Product 3]]
霍尔格:

第一步,我不会关注Java 8的新功能,而是关注Java 5+的功能。Iterator可以使用for-each时不要处理通常,不要迭代keySet()对每个键执行映射查找,因为您可以迭代entrySet()不需要任何查找。另外,IntSummaryStatistics当您只对最大值感兴趣时,也不要询问并且不要迭代两个数据结构中较大的一个,只是要重新检查一下您在每次迭代中都没有超出较小的结构。

Map<String, Integer> colWidths = rows.
        stream().
        flatMap(m -> m.entrySet().stream()).
        collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().size(), Integer::max));
int tableWidth = colWidths.values().stream().mapToInt(Integer::intValue).sum();
String[][] array = new String[rows.size()][tableWidth];

int rowIdx = 0;
for(TreeMap<String, List<String>> row: rows) {
    int cellIdx = 0;
    for(Map.Entry<String,Integer> e: colWidths.entrySet()) {
        String col = e.getKey();
        List<String> cells = row.get(col);
        int index = cellIdx;
        if(cells != null) for(String s: cells) array[rowIdx][index++]=s;
        cellIdx += colWidths.get(col);
    }
    rowIdx++;
}
return array;

我们可以通过使用映射到列位置而不是宽度来进一步简化循环

Map<String, Integer> colPositions = rows.
        stream().
        flatMap(m -> m.entrySet().stream()).
        collect(Collectors.toMap(e -> e.getKey(),
                                 e -> e.getValue().size(), Integer::max, TreeMap::new));
int tableWidth = 0;
for(Map.Entry<String,Integer> e: colPositions.entrySet())
    tableWidth += e.setValue(tableWidth);

String[][] array = new String[rows.size()][tableWidth];

int rowIdx = 0;
for(Map<String, List<String>> row: rows) {
    for(Map.Entry<String,List<String>> e: row.entrySet()) {
        int index = colPositions.get(e.getKey());
        for(String s: e.getValue()) array[rowIdx][index++]=s;
    }
    rowIdx++;
}
return array;

标头数组可以进行以下更改:

Map<String, Integer> colPositions = rows.stream()
    .flatMap(m -> m.entrySet().stream())
    .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().size(),
                              Integer::max, TreeMap::new));
String[] header = colPositions.entrySet().stream()
    .flatMap(e -> Collections.nCopies(e.getValue(), e.getKey()).stream())
    .toArray(String[]::new);
int tableWidth = 0;
for(Map.Entry<String,Integer> e: colPositions.entrySet())
    tableWidth += e.setValue(tableWidth);

String[][] array = new String[rows.size()+1][tableWidth];
array[0] = header;

int rowIdx = 1;
for(Map<String, List<String>> row: rows) {
    for(Map.Entry<String,List<String>> e: row.entrySet()) {
        int index = colPositions.get(e.getKey());
        for(String s: e.getValue()) array[rowIdx][index++]=s;
    }
    rowIdx++;
}
return array;

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将 List<List<TextValue>> 转换为 List<Map<String, String>>

Java将List <String>转换为Map <String,String>

将Map <String,Object>转换为Map <String,List <Object >>

Java-8流:将List <{String,List <String>}>转换为Map <String,List <String >>

将“ Map <String,List <String >>”强制转换为“ Map <String,List <String >>”

Kotlin FP:将List <String>转换为Map <String,Int>

将List <Map <String,Object >>转换为String [] []

将List <String>转换为Map <String,Integer>

Scala - 将 List[((String, String), Double)] 转换为 List[String,Map[String,Double]]

如何将List <Map <String,Object >>转换为List <Map <String,String >>

使用Terraform将列表(map(list(map(string()))))转换为map(list(map(string))))

Java8:通过联接值将Map <String,List <String >>转换为Map <String,String>

Java-8流:将Map <String,List <List <DataType >>>转换为Map <String,List <DataType >>

Groovy 2 List 转换为 Map(String,List<String>)

将 List<List<String>> 转换为 String[][]

如何将 List<Map<String,Object>> 转换为 Map<String, String>?

如何将List <Map <?,?>>转换为List <Map <String,String >>?

将 byte[] 转换为 List<Map<String, Object>>

Java:如何将List <?>转换为Map <String,?>

将list <map <string,object >>转换为POJO类的对象

使用Dart将String转换为List / Map

将 Stream<QuerySnapshot<Map<String, dynamic>>> 转换为 List?

将 JSON 数据转换为 List<Map<String, dynamic>>

在Kotlin中将Map <String,List <String >>转换为List <Map <String,String >>

如何将具有类似键的List <Map <String,String >>转换为Map <String,List <String >>?

颤振类型转换为 List<Map<String, String>>

使用Java 8流API将List <Map <String,Object >>转换为Map <String,List <Map <String,Object >>>

将Json转换为Map [String,String]

将Map <String,String>转换为POJO