Converting from csv to json by using map for more

2020-07-23 04:41发布

I have a csv file which has contents like :

Fruit, Mango
Fruit, Apple
Car, Audi
Apple, Red
Color, Brown

I want to eventually convert it in a format like this :

"hierarchy" : [{
   "label": "Fruit",
   "children" : [ {label: "Mango"}, {label: "Apple", "children": [ {label:"Red"}]}
   ]
},
{
   "label" : "Car",
   "children" : [ {label: "Audi"}
   ]
},
{
   "label" : "Color",
   "children" : [ {label: "Brown"}
   ]
}]

To do this, I have inserted the values in the map :

StringBuilder sb = new StringBuilder();
String line = br.readLine();
 while (line != null) {
            sb.append(line);
            sb.append("\n");
            line = br.readLine();
        }

String[] contents=(sb.toString().split("\n"));
String[] newContents;

 Map<String, List<String>> myMaps = new LinkedHashMap<String, List<String>>();


for(String s : contents)
{
  newContents= s.split(",");
    if (!myMaps.containsKey(newContents[0])) {
            myMaps.put(newContents[0], new ArrayList<String>());
        }
        myMaps.get(newContents[0]).add(newContents[1]);
}

This will basically convert the file to a map in the form of parent (key) and child (values). I was however wondering how to deal with the case when there is more than 1 level of depth - For example in my given csv? Will a map work in this case or is there a better approach?

3条回答
我欲成王,谁敢阻挡
2楼-- · 2020-07-23 05:15

Your JSON structure looks more like a tree, that can be desined as a class:

public class Node {
    private String label;
    private List<Node> children; // can also be of type Node[]

    // getters, setters
}

then hierarchy is an array or List of nodes

List is preferred over array, because it is easier to use during population of children

UPDATE: The full example on how to populate the Tree using Node class:

public class Node {
    private String label;
    private List<Node> children = new ArrayList<>(); // to avoid checks for null

    public String getLabel() {
        return label;
    }
    public void setLabel(String label) {
        this.label = label;
    }
    public List<Node> getChildren() {
        return children;
    }
    public void setChildren(List<Node> children) {
        this.children = children;
    }
}

class Converter {
    public List<Node> fromCsvFile(String filename) throws IOException {
        Node root = new Node();

        BufferedReader input = new BufferedReader(new FileReader(filename));
        String[] entry;

        String line = input.readLine();
        while (line != null) {
            entry = line.split(",");

            // find or create
            Node node = findByLabel(root, entry[0]);
            if (node == null) {
                // top level
                node = new Node();
                node.setLabel(entry[0]);
                root.getChildren().add(node);
            }

            // add child
            Node child = new Node();
            child.setLabel(entry[1]);
            node.getChildren().add(child);

            // next line
            line = input.readLine();
        }

        return root.getChildren();
    }

    public Node findByLabel(Node node, String label) {
        if (label.equals(node.getLabel())) {
            return node;
        }

        for (Node child : node.getChildren()) {
            // recursion
            Node found = findByLabel(child, label);
            if (found != null) {
                return found;
            }
        }

        return null;
    }
}

Note: You do not need explicit Node, and you can use Map<String, Object> where a value can contain nested maps, or List of children, or String value for label. But using an explicit class is cleaner.

Alternative to recursive lookup for an existing node in the tree, an independent flat collection (Map) can be created to speed up lookups:

class Converter {
    public List<Node> fromCsvFile(String filename) throws IOException {
        Node root = new Node();
        Map<String, Node> existingNodes = new HashMap<>();

        BufferedReader input = new BufferedReader(new FileReader(filename));
        String[] entry;

        String line = input.readLine();
        while (line != null) {
            entry = line.split(",");

            // find or create
            Node node = existingNodes.get(entry[0]);
            if (node == null) {
                // new top level node
                node = new Node();
                node.setLabel(entry[0]);
                root.getChildren().add(node);
                existingNodes.put(entry[0], node);
            }

            // add child
            Node child = new Node();
            child.setLabel(entry[1]);
            node.getChildren().add(child);
            existingNodes.put(entry[1], child);

            // next line
            line = input.readLine();
        }

        return root.getChildren();
    }
}

Just for reference: Full example

查看更多
走好不送
3楼-- · 2020-07-23 05:26

Try this.

String csv = ""
    + "Fruit, Mango\n"
    + "Fruit, Apple\n"
    + "Car, Audi\n"
    + "Apple, Red\n"
    + "Color, Brown\n"
    + "Red, Fire\n";
Set<String> topLevels = new LinkedHashSet<>();
Set<String> notTopLevels = new LinkedHashSet<>();
Map<String, Map<String, Object>> labels = new LinkedHashMap<>();
try (BufferedReader reader = new BufferedReader(new StringReader(csv))) {
    String line;
    while ((line = reader.readLine()) != null) {
        String[] fields = line.split("\\s*,\\s*");
        Map<String, Object> value = labels.computeIfAbsent(
            fields[1], k -> new LinkedHashMap<String, Object>());
        labels.computeIfAbsent(
            fields[0], k -> new LinkedHashMap<String, Object>())
            .put(fields[1], value);
        topLevels.add(fields[0]);
        notTopLevels.add(fields[1]);
    }
}
Map<String, Object> hierarchy = new LinkedHashMap<>();
topLevels.removeAll(notTopLevels);
for (String s : topLevels)
    hierarchy.put(s, labels.get(s));
System.out.println(hierarchy);

result:

{Fruit={Mango={}, Apple={Red={Fire={}}}}, Car={Audi={}}, Color={Brown={}}}
查看更多
爷、活的狠高调
4楼-- · 2020-07-23 05:39

Map is fine. Just use recursive function to write deeper levels.

查看更多
登录 后发表回答