【问题标题】:How to process object with map for CSV output如何使用地图处理对象以进行 CSV 输出
【发布时间】:2021-02-05 23:45:07
【问题描述】:

我有一组以下对象,我需要将其写入 CSV:

public class OutputObject {
    private String userId;
    private Map<String, Object> behaviour;
}

上面的集合可以有一个包含两个、三个或四个值的映射。

[
OutputObject1 [userId=11, behaviours={color=white, size=S, owner=Mr. A}], 
OutputObject2 [userId=22, behaviours={color=black, isNew=true}],
OutputObject3 [userId=33, behaviours={color=green, size=L}]
]

需要 CSV 输出:

userId, color, size, owner, isNew
11,     white,  S,   Mr. A,
22,     black,   ,        , true
33,     green,  L,        ,

我从下面的 sn-p 开始打印出来:

     // Set<OutputObject> outputObjectSet already received.
     JSONArray jsonArrayObject = new JSONArray(outputObjectSet);
     String csvValue = CDL.toString(jsonArrayObject);
     FileWriter fileWriter = new FileWriter(fileObject, true);
     fileWriter.write(csvValue);
     fileWriter.close();

但上面是创建一个两列 csv,其中 userIdbehaviours 打印所有地图对象 behaviours。如何实现上述类型的输出。

由于集合中可能包含大量此类对象,如何有效地做到这一点。

【问题讨论】:

    标签: java arrays json set export-to-csv


    【解决方案1】:

    这应该非常有效,即使对象数量更多,因为 Java 的 HashMapArrays.sort() 实现非常快。请注意,此实现依赖于 Apache 的 common-text-library 来转义内容。

    private static void outputCSV(List<OutputObject> objects, PrintStream output) {
        AtomicInteger highestBehaviourIndex = new AtomicInteger();
    
        HashMap<String, Integer> behaviourIndexMap = new HashMap<>();
    
        // Give every behaviour an index
        for (OutputObject object : objects) {
            object.getBehaviour().forEach((name, value) -> behaviourIndexMap.computeIfAbsent(name, (unused) -> highestBehaviourIndex.getAndIncrement()));
        }
    
        String[] behaviours = new String[highestBehaviourIndex.get()];
    
        behaviourIndexMap.forEach((name, index) -> {
            behaviours[index] = name;
        });
    
        output.println("userId, " + String.join(", ", behaviours));
    
        // Sort by ID
        objects.sort(Comparator.comparingInt(OutputObject::getUserId));
    
        for (OutputObject object : objects) {
            // Print line
            StringJoiner joiner = new StringJoiner(", ");
            
            for (String behaviour : behaviours) {
                joiner.add(StringEscapeUtils.escapeCsv(object.getBehaviour().getOrDefault(behaviour, "").toString()));
            }
            
            output.println(object.getUserId() + ", " + joiner.toString());
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      在这里使用 JSONArray 似乎是多余的,您可以实现一个辅助方法将OutputObject 序列化为 CSV 字符串,同时考虑到需要维护列的顺序:

      public class CSVSerializer {
          public static String transform(OutputObject obj) {
              String[] fields = {"color", "size", "owner", "isNew"};
              return Stream.concat(
                      Stream.of(obj.getUserId()), 
                      Arrays.stream(fields)
                            .map(f -> obj.getBehaviour().get(f))
                            .map(v -> v == null ? "" : v.toString()) 
                     )
                     .collect(Collectors.joining(","));
          }
      }
      
      
      String csv = outputObjectSet.stream()
                                  .map(CSVSerializer::transform)
                                  .collect(Collectors.joining("\n"));
      // print csv contents
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多