2

I am having some issues even starting with this task so I thought some of you might help. Basically I am given a .csv file like in the example below and it should be displayed like int the example output.

Here is the content of the .csv file:

The first is the ID, Second menuname, third is Parent ID (if its a number it should be that number's child), and if Hidden is true it should not display.

ID;MenuName;ParentID;isHidden;LinkURL
1;Company;NULL;False;/company
2;About Us;1;False;/company/aboutus
3;Mission;1;False;/company/mission
4;Team;2;False;/company/aboutus/team
5;Client 2;10;False;/references/client2
6;Client 1;10;False;/references/client1
7;Client 4;10;True;/references/client4
8;Client 5;10;True;/references/client5
10;References;NULL;False;/references

Here is the output:

. Company 
.... About Us 
....... Team 
.... Mission 
. References 
.... Client 1 
.... Client 2
  • The menu items should be indented depending on the parent they belong under.
  • Some items are hidden, and should not be presented
  • The items should be ordered alphabetically

Can you guys point me out how to start and what data structures to use (I was having in mind Stack) but I am not sure. Thanks!

Here is my code so far.

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Stack;


public class Main {

    static void Function() {


    }

    public static void main(String[] args) throws IOException {
    // write your code here

        BufferedReader csvReader = new BufferedReader(new FileReader("Navigation.csv"));
        String row;
        int parent_id = 0;
        Stack stack = new Stack();

        while ((row = csvReader.readLine()) != null) {
            String[] data = row.split(";");
            stack.push(row);


            for(int i=0; i<4; i++){
                System.out.print(data[i] + " ");
                if(data[2].equals("NULL")){
                    parent_id = Integer.parseInt(data[0]);
                }
            }
            System.out.println(parent_id);

        }
        csvReader.close();


        for(int i=0;i<10;i++){
            System.out.println(stack.pop());
        }
    }
}

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Ok, you start with a Class and a static main method. Show us where you're stuck from there. – Gilbert Le Blanc Jun 13 '20 at 08:24
  • Hello, you may want to use tree structure actually as shown [here](https://stackoverflow.com/questions/1005551/construct-a-tree-structure-from-list-of-string-paths) - you have similar path structure in `LinkUrl` column – Nowhere Man Jun 13 '20 at 08:36
  • No, I am not that stuck haha. I've managed to read the cvs file and everything but I dont know how to approach the problem from logical stand point. I added my code above. I tried couple of things btw, it doesn't have to mean anything. – Filip Petreski Jun 13 '20 at 08:39

3 Answers3

0

For parsing the CSV in java, you can use a third party library like Apache Commons. It provides a mechanism to fetch via Headers.

As a data structure to store this, you can use Map with Key as int (assuming ID is int) and Value as a POJO which has a class structure as follows:

   class MenuItem {
    Node node;
    List<Node> childNodes;
}

Where Node is defined as:

   class Node {
    String menuName;
    Boolean isHidden;
    String url;
    }

For root nodes, childNodes will be null

NOTE: The second half of the solution is based on the assumption that your Node can only be one layer deep (as per the example provided).

Rothin Sen
  • 444
  • 4
  • 8
0

This what you can do:

  1. Define a class Item (you can use Node)

    class Item {
     int id;
     String name;
     int parentId;
     String link;
     boolean hidden;
     List<Item> children;
    }
    
  2. Read the CSV and create a list of items Item (we are doing is step 2 and step 3 separately as in your CSV the parent items are in random order)

    List<Item> items = new ArrayList<Item>();
    items.add(new Item(id, name, parentId, link, hidden)); // get these values from CSV, set parentId as `0` if it is null
    
    items = items.stream().sorted((a, b) -> a.parentId - b.parentId)).collect(Collectors.toList()); // sort item by ascending order of parentId
    
  3. Create a new list with hierarchy

    List<Item> treeHireachy  = new ArrayList<Item>();
    // iterate through the previous list and add only first level items to this list.
    // then add remaining items as child nodes/item to based on the appropriate parent item
    
Nikhil
  • 1,126
  • 12
  • 26
0

It is a bit difficult to do this with a single collection of items.

Not only do you need a mapping for each item (id --> MenuItem), but also a way to sort MenuItems by their MenuName. On top of that, you need to maintain a tree structure of the hierarchy.

I propose two collections: a Map<Integer, MenuItem> and a SortedSet<MenuItem>. In order to build the hierarchy tree, loop through the set and add children to their parents until you're left with only the root MenuItems - the ones without a parent.

The actual printing should be clear enough - you recursively print all subtrees of MenuItems.

Here is my solution. This is how you run it: java MenuItems < "your_csv_file"

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

public class MenuItems {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // skip the header line
        sc.nextLine();

        // Read all menu items
        SortedSet<MenuItem> menuItemsSet = new TreeSet<MenuItem>();
        Map<Integer, MenuItem> menuItemsMap = new HashMap<Integer, MenuItem>();
        while (sc.hasNextLine()) {            
            MenuItem nextItem = new MenuItem(sc.nextLine().split(";"));
            menuItemsSet.add(nextItem);
            menuItemsMap.put(nextItem.id, nextItem);
        }

        // build tree structure
        Set<MenuItem> reunitedChildren = new HashSet<MenuItem>();
        for (MenuItem nextItem : menuItemsSet) {
            // if an item has a parent
            if (nextItem.parentId != -1) {
                menuItemsMap.get(nextItem.parentId).addChild(nextItem);
                reunitedChildren.add(nextItem);
            }
        }
        menuItemsSet.removeAll(reunitedChildren);

        // print result:
        printMenu(" ", menuItemsSet);
    }

    private static void printMenu(String indent, SortedSet<MenuItem> subtree) {
        for (MenuItem nextItem : subtree) {
            if (!nextItem.isHidden) {
                System.out.println(indent + " " + nextItem.menuName);
                if (!nextItem.children.isEmpty()) {
                    printMenu(indent + "   ", nextItem.children);
                }
            }
        }
    }
}

class MenuItem implements Comparable<MenuItem> {
    int id;
    String menuName;
    int parentId;
    boolean isHidden;
    String linkUrl;

    SortedSet<MenuItem> children;

    public MenuItem(String[] fields) {
        this(
            Integer.parseInt(fields[0]),
            fields[1],
            fields[2].equals("NULL") ? -1 : Integer.parseInt(fields[2]),
            Boolean.parseBoolean(fields[3]),
            fields[4]
        );
    }

    public MenuItem(
        int id,
        String menuName,
        int parentId,
        boolean isHidden,
        String linkUrl
    ) {
        this.id = id;
        this.menuName = menuName;
        this.parentId = parentId;
        this.isHidden = isHidden;
        this.linkUrl = linkUrl;
        this.children = new TreeSet<MenuItem>();
    }

    public void addChild(MenuItem child) {
        this.children.add(child);
    }

    @Override
    public boolean equals(Object obj) {
        MenuItem that = (MenuItem) obj;
        return this.id == that.id;
    }

    @Override
    public int hashCode() {
        return this.id;
    }

    @Override
    public int compareTo(MenuItem that) {
        return this.menuName.compareTo(that.menuName);
    }
}
Janez Kuhar
  • 3,705
  • 4
  • 22
  • 45