行转列的三种实现方式
上次项目中,碰到了需要将取出的数据进行行转列的操作,然后显示出来的问题,当时是吧这个问题交给了前端小姐姐,麻烦她来处理了,但是后来抽空自己研究了一下,发现其实有三种实现方式,下面直接上代码一一说明,以供参考
(一)、直接在SQL语句里面转,返回经过转换,想要的数据格式
(二)、取出原数据后,传到前端用JS转——笔者这种转的想法来自基于行列式的转置矩阵的实现原理(是不是后悔大学没好好学哈0.0)
这里方便大家看懂,多唠叨几句,这是需要进行转换的表格数据
下面是实现行转列的主要JS代码:
//点击按钮实现行列转换 $('#changeBtn').on('click', function(e) { //先把原表格的内容存进数组set(有种简单的,吧表头的th标签全部改成td,但表头的字体会失去样式) var set = []; $('table tr').each(function() { var row = []; $(this).find('th').each(function() { row.push($(this).text()); }); $(this).find('td').each(function() { row.push($(this).text()); }); set.push(row); }); //$("#testDiv").after("一行二列:"+set[0][1]); //$("#testDiv").after("二行五列:"+set[1][4]); var seted = []; //确定新数组有多少行 for(var i=0;i<set[1].length;i++){ seted[i] = []; } //遍历原数组,动态添加数据(并实现行列转换) for(var i=0;i<set.length;i++){ for(var j=0;j<set[i].length;j++){ seted[j][i] = set[i][j]; } } //把转换后的新数组的内容,显示出来 var reShow = "<table class='table table-striped table-bordered dt-responsive nowrap order-column'><tbody>"; $.each(seted, function(index, itr){ reShow += "<tr>"; $.each(itr, function(index, itd){ reShow += '<td>'+itd+'</td>'; }) reShow += "</tr>"; }) reShow += "</tbody></table>"; $("#testDiv").after(reShow); });
下面是主要的HTML代码,有强迫症的小伙伴可以参考下:
<table id="datatable" class="table table-striped table-bordered dt-responsive nowrap order-column" cellspacing="0" width="100%"> <thead> <tr> <th>网站</th> <th>年</th> <th>月</th> <th>周</th> <th>端口</th> <th>登陆人数</th> <th>在线时长</th> <th>活跃点数</th> <th>获取经验</th> <th>水晶消费</th> <th>充值人数</th> </tr> </thead> <tbody> <#list initData as app> <tr data-id='666'> <td>${app.webName}</td> <td>${app.year}</td> <td>${app.month}</td> <td>${app.week}</td> <td>${app.portName}</td> <td>${app.loginNum}</td> <td>${app.onlineTime}</td> <td>${app.activePoint}</td> <td>${app.addExp}</td> <td>${app.consume}</td> <td>${app.recharge}</td> </tr> </#list> </tbody> </table> <!-- <table id="testTable" class="table table-striped table-bordered dt-responsive nowrap order-column" cellspacing="0" width="100%"> <thead id="testThead"> </thead> <tbody id="testTbody"> </tbody> </table> --> <div class="row"><button class="btn btn-default closed" id="changeBtn">行列转换</button></div> <div class="x_panel">测试DIV <div id="testDiv"></div> </div>
最后,附上转换后的图
(三)、原数据取出后,在后台进行转换(也是最合理的一种方式,但具体问题具体分析)
下面的方式,笔者以封装好了在一个main()函数里,可以直接copy过去,查看效果,不过记得导入相应的包
public class Row2Line { public static void main(String[] args) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { //你提供的对象列表,需要转换的原数据 List<StudentGrand> StudentGrandList = getStudentGrandList(); //实现行转列的算法 List<List<String>> convertedTable = convert(StudentGrandList); //打印转换后的集合,查看结果 print(convertedTable); //剩下的可以根据实际需求,将转换好的集合传给前端、或随意处理 } private static List<List<String>> convert(List<StudentGrand> StudentGrandList) throws IntrospectionException, IllegalAccessException, InvocationTargetException {//取得StudentGrand的属性,当然你也可以用list = {"id", "name", ...} Field[] declaredFields = StudentGrand.class.getDeclaredFields(); List<List<String>> convertedTable = new ArrayList<List<String>>(); //多少个属性表示多少行,遍历行 for (Field field : declaredFields) { field.setAccessible(true); ArrayList<String> rowLine = new ArrayList<String>(); //list<T>多少个StudentGrand实体类表示有多少列,遍历列 for (int i = 0, size = StudentGrandList.size(); i < size; i++) { //每一行的第一列对应StudentGrand字段名 //所以新table的第一列要设置为字段名 if(i == 0){ rowLine.add(field.getName()); } //新table从第二列开始,某一列的某个值对应旧table第一列的某个字段 else{ StudentGrand StudentGrand = StudentGrandList.get(i); String val = (String) field.get(StudentGrand);//grand为int会报错 System.out.println(val); rowLine.add(val); } } convertedTable.add(rowLine); } return convertedTable; } //测试用数据,实际应该从数据库查询,传过来的 private static List<StudentGrand> getStudentGrandList () { List<StudentGrand> list = new ArrayList<StudentGrand>(); list.add(new StudentGrand("001", "toni", "语文", "98")); list.add(new StudentGrand("001", "toni", "数学", "98")); list.add(new StudentGrand("001", "toni", "外语", "98")); list.add(new StudentGrand("001", "toni", "体育", "98")); list.add(new StudentGrand("006", "amy", "语文", "98")); list.add(new StudentGrand("006", "amy", "数学", "98")); list.add(new StudentGrand("006", "amy", "外语", "98")); list.add(new StudentGrand("006", "amy", "体育", "98")); list.add(new StudentGrand("003", "安东尼", "语文", "98")); list.add(new StudentGrand("003", "安东尼", "数学", "98")); list.add(new StudentGrand("003", "安东尼", "外语", "98")); list.add(new StudentGrand("003", "安东尼", "体育", "98")); return list; } //打印查看结果 private static void print(List<List<String>> convertedTable) { //String json = JSONArray.formObject(convertedTable).toString(); for (List<String> list : convertedTable) { for (String string : list) { System.out.print(string+" "); } System.out.println(); } } }
这里结果是控制台打印出来的(想想还是附上截图吧)
下面是自定义的学生成绩实体类
public class StudentGrand { private String id; private String name; private String subject; private String grang; //get和set方法,main()中的构造方法这里省略了 }
最后,针对第三种实现方式,目前行转列的字段必须都是String类型的,这点如何兼容其他数据类型,比如上面例子中,学生成绩应该是int字段才更合理,忘高手不吝赐教
(昨天RNG2:3惜败SKT、今天WE1:3输SSG,特此记录!)