将数据可视化为图表(笔试挑战题)

编写一个程序,对于给定的一组数据和要求,输出一个以字符组成的柱状图。

输入

第一行,一个整数 N(1<=n<=20),表示这组数据的条目数。
第二行,两个字符串,用于表示数据展示在柱状图上的排序方式。第一个字符串是“Name” 或者 “Value”,表示排序的依据是数据条目的名称亦或数值;第二个字符串是 “ASC” 或者 “DESC”,表示升序或降序。
随后的 N 行,每行包含一个字符串 S 和一个数字 V,以空格分隔,表示一条数据。S 即数据条目的名称,仅包含小写字母,V 即对应的数值,是一个整数,(0<=V<=1,000,000)

输出

图表中名称区域的宽度,由这组数据中名称的最大长度决定,所有名称向右对齐, 图表中柱的最大长度为 20,每个柱的长度由该柱对应数据和这组数据中最大值(此值一定大于 0)的比值与 20 相乘获得,不足一格的部分舍去。

输入示例

3
Value DESC
apple 5
pen 3
pineapple 10

输出示例

┌─────────┬────────────────────┐
│pineapple│████████████████████│
├─────────┼────────────────────┤
│    apple│██████████          │
├─────────┼────────────────────┤
│      pen│██████              |
└─────────┴────────────────────┘

(等宽字体下,输出应当形如下图)

GrapeCity Challenge

图表外框转角符号:

  • “┌”(\u250c)
  • “┐”(\u2510)
  • “└”(\u2514)
  • “┘”(\u2518)

图表中的横、竖线:

  • “─”(\u2500)
  • “│”(\u2502)

图表中的各种交叉线:

  • “├”(\u251c)
  • “┤”(\u2524)
  • “┬”(\u252c)
  • “┴”(\u2534)
  • “┼”(\u253c)

用来拼柱子的字符:

  • “█”(\u2588)

图表中的空格:

  • “ ”(\u0020)
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

/**
 * 第一行,一个整数 N(1<=n<=20),表示这组数据的条目数。
	第二行,两个字符串,用于表示数据展示在柱状图上的排序方式。第一个字符串是“Name” 或者 “Value”,
表示排序的依据是数据条目的名称亦或数值;第二个字符串是 “ASC” 或者 “DESC”,表示升序或降序。
	随后的 N 行,每行包含一个字符串 S 和一个数字 V,以空格分隔,表示一条数据。S 即数据条目的名称,
仅包含小写字母,V 即对应的数值,是一个整数,(0<=V<=1,000,000)

	例如:3
	Value DESC
	apple 5
	pen 3
	pineapple 10
	
 * @author CGX~LL
 *
 */
public class Test {

	public static void main(String[] args) {
		
		
		// TODO Auto-generated method stub
		Scanner in = new Scanner(System.in);
		in.useDelimiter(";");//将;设置为分隔符
		String string = in.next();
		//此时可进行输入!
		
		SeePicture(string);
		in.close();
	}
	
	private static void SeePicture(String string) {
		//1.首先将这个大字符串分隔开(用\r分割)
		//2.将分割后的子字符串分别处理
		String[] temp = string.split("\r\n");
		int num = Integer.parseInt(temp[0]);//表示行数

		String sortStyle = temp[1].split(" ")[0];//表示排序方式
		String upOrDown = temp[1].split(" ")[1];//表示升序或是降序
		
		//后面的数据需要存在HashMap中进行排序
		Map<String, Integer> map = new LinkedHashMap<>();
		//从第三行数据开始插入,一直到第num行
		for(int i = 2;i<num+2;i++) {
			map.put(temp[i].split(" ")[0], Integer.parseInt(temp[i].split(" ")[1]));
		}

		//参数校验
		if(num<1 || num>20) {//按要求,行数越界了
			System.out.println("行数不在范围内,1<=num<=20");
			return;
		}
		if("Name".equals(sortStyle) == false && "Value".equals(sortStyle) == false) {//按要求,排列方式输错了
			System.out.println("请输入正确的排序方式,Name or Value");
			return;
		}
		if("ASC".equals(upOrDown) == false && "DESC".equals(upOrDown) == false) {//按要求,升序或者降序输错了
			System.out.println("请输入正确的升降序方式,ASC or DESC");
			return;	
		}		

		map = sortHashMap(map, sortStyle, upOrDown);
		
		//至此,该集合已经全部存入map(并按照指定顺序)
		//接下来进行输出
		drawResult(map,num);
}

public static Map<String,Integer> sortHashMap(Map<String,Integer> map,String sortStyle,String upOrDown)//HashMap排序
{
    List<Map.Entry<String,Integer>> list = new LinkedList<Map.Entry<String,Integer>>(map.entrySet());
    Collections.sort(list, new Comparator<Map.Entry<String,Integer>>()
    {
        @Override
        public int compare(Map.Entry<String,Integer> o1, Map.Entry<String,Integer> o2)
        {
        	if("Value".equals(sortStyle)) {//按value进行排序
        		if("ASC".equals(upOrDown)) {//升序
        			int compare = o1.getValue()-o2.getValue();
        			return compare;
        			
        		}else {//降序
        			int compare = o1.getValue()-o2.getValue();
        			return -compare;
        		}
        	}else {
        		if("ASC".equals(upOrDown)) {//按Name进行排序,升序
        			int compare = (o1.getKey()).compareTo(o2.getKey());
        			return compare;
        		}else {//降序
        			int compare = (o1.getKey()).compareTo(o2.getKey());
        			return -compare;
        		}
        	}
        }
    });

    Map<String,Integer> result = new LinkedHashMap<>();
    for (Map.Entry<String,Integer> entry : list) {
        result.put(entry.getKey(), entry.getValue());
    }
    return result;
}

	private static void drawResult(Map<String, Integer> map,int num) {//结果图
		//分别得到map中key、value的最大长度
		Set<String> set = map.keySet();
		int keyMaxSize = maxSize(set);
		Collection<Integer> set2 = map.values();
		int valueMaxSize = maxNum(set2);

		//将map中的key存入数组中,方便通过下标访问,再通过key得到value
		String[] array = getKeys(map,num);

		for(int i=1,m=0;i<2*num+2;i++) {
			if(i == 1) {//第一行
				System.out.print("\u250c");
				int j = keyMaxSize;
				while(j>0) {
					System.out.print("\u2500");
					j--;
				}
				System.out.print("\u252c");
				int k = valueMaxSize;
				while(k>0) {
					System.out.print("\u2500");
					k--;
				}
				System.out.println("\u2510");
			}
			else if(i%2 == 0) {//有数据的行
				System.out.print("\u2502");
				int j = keyMaxSize-array[m].length();
				while(j>0) {
					System.out.print(" ");
					j--;
				}
				System.out.print(array[m]);
				System.out.print("\u2502");
				int k = map.get(array[m]);
				int k2 = valueMaxSize-k;
				while(k>0) {
					System.out.print("\u2588");
					k--;
				}
				while(k2>0) {
					System.out.print(" ");
					k2--;
				}
				System.out.println("\u2502");
				m++;
			}
			else if(i == 2*num+1) {//最后一行
				System.out.print("\u2514");
				int j = keyMaxSize;
				while(j>0) {
					System.out.print("\u2500");
					j--;
				}
				System.out.print("\u2534");
				int k = valueMaxSize;
				while(k>0) {
					System.out.print("\u2500");
					k--;
				}
				System.out.println("\u2518");
			}
			else {//其他行(无数据,也不是在首行或者末行)
				System.out.print("\u251c");
				int j = keyMaxSize;
				while(j>0) {
					System.out.print("\u2500");
					j--;
				}
				System.out.print("\u253c");
				int k = valueMaxSize;
				while(k>0) {
					System.out.print("\u2500");
					k--;
				}
				System.out.println("\u2524");
			}
		}
	}

	private static int maxNum(Collection<Integer> set2) {//取得set集合中最大的值(Integer)
		Iterator<Integer> iterator = set2.iterator();
		int len = 0;
		while(iterator.hasNext()) {
			int temp = iterator.next();
			if(temp > len) {
				len = temp;
			}
		}
		return len;
	}

	private static int maxSize(Set<String> set2) {//取出set集合中长度最长数据的长度(String)
		Iterator<String> iterator = set2.iterator();
		int len = 0;
		while(iterator.hasNext()) {
			String string = iterator.next();
			int temp = string.length();
			if(temp > len) {
				len = temp;
			}
		}
		return len;
	}

	private static String[] getKeys(Map<String, Integer> map,int num) {//取得map集合中key,并将其存入数组中
		String[] array = new String[num];
		int i=0;
		Set<String> set = map.keySet();
		Iterator<String> iterator = set.iterator();
		while(iterator.hasNext()) {
			array[i++] = iterator.next();
		}
		return array;
	}
}

尝试输入几个例子看看结果:(运行环境——Eclipse)

假如故意输入错误的参数:

很明显,会得到提醒;


版权声明:本文为ChenGX1996原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。