Printing a Graph from a char[][] in Java

安稳与你 提交于 2019-12-24 19:35:51

问题


The method below loops through a given int[], storing both the frequencies of the numbers found in the array along with each different appearing number into a HashMap.

After looping, the HashMap would look something like this (num=frequency):

{0=4, 656=1, 1=1, 2=2, 3=2, 4=3, 8=1, 56=1, 75=1, 12=3, 13=1, 61=1}

Following this, the method creates a char[][], representing designated x & y coords for the size and frequency of each integer. The x axis represents the size of the number, and the y axis represents the number's frequency in the HashMap.

private static void print(int[] intArr) {
    /*
   * Purpose of method is to print:
   * The frequency of each index
   * A graphical histogram of the frequencies of each index
    */
    Map<Integer, Integer> map = new HashMap<>();
    for (int i : intArr)
        // If current index of the array being searched is found in map, +1 to total # of occurrences of that index
        if (map.containsKey(i)) map.put(i, map.get(i) + 1);
        else map.put(i, 1);

    // Iterate through all entries of map, printing the key and value of each
    for (Entry<Integer, Integer> entry : map.entrySet()) System.out.println("Frequency of index " + entry.getKey() + " is " + entry.getValue());
    System.out.println();

    char[][] graph = new char[Collections.max(map.values()) + 1][map.keySet().size() + 1];
    for (int x = 0; x < graph.length; x++)
        for (int y = 0; y < graph[x].length; y++) {
            graph[x][y] = ' ';
            // if (....) graph[x][y] = '*';
            // else graph[x][y] = ' ';
        }
    // Create borders
    for (int i = 0; i < graph.length; i++) graph[i][0] = '|';
    graph[graph.length - 1][0] = '+';
    for (int i = 1; i < graph[0].length; i++) graph[graph.length - 1][i] = '-';
    // Print graph into console
    for (int x = 0; x < graph.length; x++) {
        for (int y = 0; y < graph[0].length; y++) System.out.print(graph[x][y]);
        System.out.println();
    }
}

The output of the code is like so:

Frequency of index 0 is 4
Frequency of index 656 is 1
Frequency of index 1 is 1
Frequency of index 2 is 2
Frequency of index 3 is 2
Frequency of index 4 is 3
Frequency of index 8 is 1
Frequency of index 56 is 1
Frequency of index 75 is 1
Frequency of index 12 is 3
Frequency of index 13 is 1
Frequency of index 61 is 1

|            
|            
|            
|            
+------------

Now the problem I'm having is that I can't seem to figure out how to plot an asterisk at the corresponding x & y coords where they are needed. I want the graph to look like this instead:

|*           
|     *   *  
|   **       
| **   *** **
+------------

What I need is a proper if statement checking if the current coordinate being printed is that of the proper column and row, and if not, then print an empty space. As of now, all the program does is fill in everything with empty spaces. I've tried messing around with the code a lot, but it mostly just ended with bugs and ArrayIndexOutOfBounds exceptions.


回答1:


Should work by inserting something like this before printing:

for (Entry<Integer, Integer> entry : map.entrySet()) {
  int index = entry.getKey();
  int frequency = entry.getValue();
  if (frequency < graph.length && index < graph[frequency].length) {
    graph[frequency][index] = '*'; 
  }
}

If you really want this in the setup loop (which I wouldn't do because it seems less readable), you can do something like this:

for (int x = 0; x < graph.length; x++) {
  Integer freq = map.get(x);
  int f = freq == null ? 0 : freq;
  for (int y = 0; y < graph[x].length; y++) {
     graph[x][y] = y == f ? '*' : ' ';
  }
}

The reason for your OOB exceptions is probably that the graph array is smaller than your numbers; typical reasons:

  • off by one errors
  • coordinate mixups
  • insufficient array size

Note that the code fragments don't mirror the y coordinates as doing so when printing seems easier than mirroring them in all other places.

Edit: To fix the size, change the code to

char[][] graph = new char[Collections.max(map.values()) + 1]
                         [Collections.max(map.keySet()) + 1];

Or keep track of the size in ine of the earlier loops.




回答2:


First of all you won't be able to display your indices that are too big if you use a small array for display.

private static void print(int[] intArr) {
    Map<Integer, Integer> map = new HashMap<>();

    for (int i : intArr) {
        if (map.containsKey(i)) { 
            map.put(i, map.get(i) + 1);
        } else { 
            map.put(i, 1);
        }
    }

    // Define the 2d array here (NB: that this is not the correct wanted size, you should use the max for keys and values to have a correct and meaningful display)
    char[][] graph = new char[Collections.max(map.values()) + 1][map.keySet().size() + 1];

    for (Entry<Integer, Integer> entry : map.entrySet()) {
        int key = entry.getKey();
        int value = entry.getValue();
        System.out.println("Frequency of index " + key + " is " + value);
        // We set the '*' value here (NB: The +1 are there to take the border into account -> And so we will put the border at 0 on each axis)
        graph[key+1][value+1] = '*';
    }

    System.out.println();

    // Create the borders
    for (int i = 0; i < graph.length; i++) { 
        graph[i][0] = '|'; 
        graph[graph.length - 1][0] = '+'; 
    }
    for (int j = 1; i < graph[0].length; j++) { 
        graph[0][j] = '-'; 
    }

    // Print graph into console --> Reverse the y because of what we setted
    for (int x = 0; x < graph.length; x++) {
        for (int y = graph[0].length-1; y >= 0; y--) {
            System.out.print((graph[x][y] != '') ? graph[x][y]:' ');
        }
        System.out.println();
    }
}



回答3:


First, you figure out the maximum X value (656), and the maximum Y value (4).

Then you create a 2D array to store the graph, with space for the axes. Since the minimum Y value is 1, that means maxY rows plus one row for the axis. Since the minimum X value is 0, that means maxX + 1 columns plus one column for the axis.

Then you fill the graph with spaces, and "draw" the border.

Finally, you add a * according to the key (x) and value (y) in the Map, with adequate offsets.

To make it easier, build the graph with the axes at index 0 in the arrays.

Like this:

private static void printGraph(Map<Integer, Integer> input) {
    // Find max X and max Y
    int maxX = input.keySet().stream().max(Integer::compare).get();
    int maxY = input.values().stream().max(Integer::compare).get();

    // Create graph 2D matrix
    char[][] graph = new char[maxY + 1][maxX + 2];

    // Draw X axis and origin point
    Arrays.fill(graph[0], '-');
    graph[0][0] = '+';

    // Fill graph with spaces and draw Y axis
    for (int i = 1; i < graph.length; i++) {
        Arrays.fill(graph[i], ' ');
        graph[i][0] = '|';
    }

    // Plot input values
    for (Entry<Integer, Integer> entry : input.entrySet())
        graph[entry.getValue()][entry.getKey() + 1] = '*';

    // Print graph (upside-down)
    for (int i = graph.length - 1; i >= 0; i--)
        System.out.println(graph[i]);
}

Test

int[][] data = { { 0, 4 }, { 656, 1 }, { 1, 1 }, { 2, 2 }, { 3, 2 }, { 4, 3 },
                 { 8, 1 }, { 56, 1 }, { 75, 1 }, { 12, 3 }, { 13, 1 }, { 61, 1 } };
Map<Integer, Integer> input = new HashMap<>();
for (int[] d : data)
    input.put(d[0], d[1]);
printGraph(input);

Output

|*                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
|    *       *                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
|  **                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
| *      *    *                                          *    *             *                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    *
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


来源:https://stackoverflow.com/questions/47166907/printing-a-graph-from-a-char-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!