背景描述
如下表所示,有多条我国各省市下面区名,不难发现,它们都是混乱列出的,并没有一定的规则;一个区是由(省,市,区)这个三维坐标才能唯一确定。在工作中可能会遇到不少这种三维坐标的模型,这里只是用这种大家最为熟悉的行政区的示例来阐述,如何让三维坐标的模型以树形结构展示,这是本文所讨论的主题。
省 | 市 | 区 |
---|---|---|
陕西省 | 西安市 | 未央区 |
江苏省 | 南京市 | 鼓楼区 |
广东省 | 广州市 | 天河区 |
四川省 | 成都市 | 武侯区 |
江苏省 | 南京市 | 秦淮区 |
江苏省 | 苏州市 | 姑苏区 |
陕西省 | 西安市 | 雁塔区 |
广东省 | 广州市 | 越秀区 |
四川省 | 成都市 | 锦江区 |
广东省 | 深圳市 | 南山区 |
陕西省 | 西安市 | 碑林区 |
四川省 | 绵阳市 | 游仙区 |
解决思路
此问题的解决思路并不难想到,可以大致分为两步:
- 数据排序
- 有序数据树形展示
数据排序
三维坐标(x, y, z)按树形展示,就是按x,y,z的层级展示,那么就要对x,y,z坐标排序,这里定义一种(x, y, z)的序关系,如下所述:
- x坐标越小,排序越靠前;
- 若x坐标相等,再比较y坐标,y坐标越小越靠前;
- 若y坐标相等,再比较z坐标,z坐标越小越靠前。
- 若z坐标也相等,则按出现的先后顺序排序。
例如(1,2,1)是要排在(2,1,1)前面的,因为前者的x坐标小于后者的x坐标。
回到行政区的示例中,我们可以使用汉语拼音首字母序来定义行政区排序,即:首字母排序越靠前,行政区越靠前,那么我们可以很容易将上面杂乱的行政区排好序,如下:
省 | 市 | 区 |
---|---|---|
江苏省 | 南京市 | 鼓楼区 |
江苏省 | 南京市 | 秦淮区 |
江苏省 | 苏州市 | 姑苏区 |
广东省 | 广州市 | 天河区 |
广东省 | 广州市 | 越秀区 |
广东省 | 深圳市 | 南山区 |
四川省 | 成都市 | 锦江区 |
四川省 | 成都市 | 武侯区 |
四川省 | 绵阳市 | 游仙区 |
陕西省 | 西安市 | 碑林区 |
陕西省 | 西安市 | 未央区 |
陕西省 | 西安市 | 雁塔区 |
有序数据树形展示
当排序结束后,其实我们肉眼已经可以很容易看出来这个树形结构了,如下图所示,但是如何用程序实现这一过程呢?
- 江苏省
- 南京市
- 鼓楼区
- 秦淮区
- 苏州市
- 姑苏区
- 南京市
- 广东省
- 广州市
- 天河区
- 越秀区
- 深圳市
- 南山区
- 广州市
- 四川省
- 成都市
- 锦江区
- 武侯区
- 绵阳市
- 游仙区
- 成都市
- 陕西省
- 西安市
- 碑林区
- 未央区
- 雁塔区
- 西安市
首先,定义行政区示例中一些主要的数据结构,如下:
List<Province> provinceList;
public class Record {
private String provinceName;
private String cityName;
private String districtName;
}
public class Province {
private String provinceName;
private List<City> cityList;
}
public class City {
private String cityName;
private List<District> districtList;
}
public class District {
private String districtName;
}
然后,通过对于有序三维数据进行一次遍历,即可得到树形结构的展示结果。
int currentProvinceIndex = -1;
int currentCityIndex = -1;
Set<String> provinceNameSet = new HashSet<>;
Set<String> cityNameSet = new HashSet<>;
Set<String> districtNameSet = new HashSet<>;
List<Province> resultList = new ArrayList();
for (Record record : recordList) {
if (!provinceNameSet.contains(record.getProvinceName())) {
currentProvinceIndex++;
provinceNameSet.add(record.getProvinceName());
Province province = new Province();
List<City> cityList = new ArrayList();
province.setProvinceName(record.getProvinceName());
province.setCityList(cityList);
resultList.add(province);
currentCityIndex = -1;
cityNameSet.clear();
}
if (!cityNameSet.contains(record.getCityName())) {
currentCityIndex++;
cityNameSet.add(record.getCityName());
City city = new City();
List<District> districtList = new ArrayList();
city.setDistrictList(districtList);
resultList.get(currentProvinceIndex).getCityList().add(city);
districtNameSet.clear();
}
if (!districtNameSet.contains(record.getDistrictName())) {
resultList.get(currentProvinceIndex).getCityList()
.get(currentCityIndex).getDistrictList.add(record.getDistrictName());
}
}
本文只是为了更为形象和生动的描绘,选取了行政区这个例子,实际上对于所有三维坐标树形展示的问题,都可以参考本文的思路,根据具体问题,定义好数据结构以及它们之间的大小关系,然后遍历一次即可得到树形的展示结果。