请选择 进入手机版 | 继续访问电脑版

设为首页 收藏本站
思科服务支持社区 点击关注
思科服务支持社区

  
 找回密码
 立即注册

扫一扫,访问微社区

搜索
热搜: 邮件服务器
查看: 946|回复: 4

【原创】【小目标,一个“译”】+ 用Java Steams创建数据透视表

[复制链接]
发表于 2018-1-31 18:13:33 | 显示全部楼层 |阅读模式
本帖最后由 julianchen 于 2018-2-1 09:58 编辑

引言:众所周知,数据透视表很适合于数据的汇总。你可以使用Streams来创建数据透视表,对各种数据进行准备和排序,使之表现出更为易读的格式。
这次让我们来看看如何使用Java 8 Streams(流)来实现一张数据透视表。通常情况下,原始数据本身一般并不容易被人们所读懂,因此我们需要进行一些数据聚合操作来辨别出原始数据中的各种规律模式。而数据透视表就是这样一种工具,它运用聚合的方法来展示出各种可视的图形和图表。
在过往的文章中,我们曾展示过如何使用Java 8 Streams进行类似SQL的效果对原始数据进行切割与分解。而今天的文章就建立在那些例子之上,如果你觉得这些对你有些难度的话,我建议你先通过如下链接浏览那两篇文章。
如果你不喜欢使用这种“原始数据”的方法来创建一张数据透视表,而选择使用Excel来实现的话,我为你提供了另外的备选方案,请参考如下链接:
CSV数据表示为POJO
我们用如下的POJO(简单的Java对象,PlainOrdinary Java Object)来表示棒球运动员及其工资。
public class Player {
    private int year;
    private String teamID;
    private String lgID;
    private String playerID;
    private int salary;
    // defined getters and setters here
}

它的数据来自于一个简单的CSV文件,该文件内既没有引用的字段,也没有多行的字段,而且单个字段中还不存在着逗号。我们可以使用一个简单的正则表达式模式来解析该CSV文件,并将数据加载到一个列表之中。其数据看起来如下所示,它一共有大约26428行:
yearIDteamIDlgIDplayerIDsalary
1985ATLNLbarkele01870000
1985ATLNLbedrost01550000
1985ATLNLbenedbr01545000
1985ATLNLcampri01633333
1985ATLNLceronri01625000
...

我们用类似于如下代码的Streams加载CSV的数据:
Pattern pattern = Pattern.compile("");
try (BufferedReader in = newBufferedReader(new FileReader(filename));){
   List<layer> players = in
       .lines()
       .skip(1)
       .map(line -> {
               String[] arr = pattern.split(line);
               return new Player(Integer.parseInt(arr[0])
                                  arr[1
                                  arr[2
                                  arr[3
                                  Integer.parseInt(arr[4]));
           })
       .collect(Collectors.toList());
}

定义数据透视表列的类
我们使用下面的类来定义数据透视表的各个列容器的类。这些列是用于对数据进行分组的。如果你使用的是SQL的话,这些列将出现在“GROUP BY”的语句中。
public class YearTeam
{
    public int year;
    public String teamID;
    public YearTeam(int yearString teamID) {
        this.year = year;
        this.teamID = teamID;
    }
    @Override
    public boolean equals(Object other)
    {
        if ( other == null ) return false;
        if ( this == other ) return true;
        if ( other instanceof YearTeam ) {
           YearTeam yt = (YearTeam)other;
            if ( year ==yt.year && teamID.equals(yt.teamID) )
               return true;
        }
        return false;
    }
    @Override
    public int hashCode()
    {
        int hash = 1;
        hash= hash * 17 + year;
        hash= hash * 31 + teamID.hashCode();
        return hash;
    }
    @Override
    public String toString()
    {
        StringBuilder sbuf = new StringBuilder();
       sbuf.append('[').append(year).append(" ").append(teamID)
           .append(']');
        return sbuf.toString();
    }
}

仅仅是为了方便起见,这些字段被定义为了“public(公有)”访问属性。而对于你自己的应用程序,你完全可以将其设置为“private(私有)属性,并根据需要添加getter/setter
这个类覆盖重写了equals()hashCode(),因为它将在存储一张Map(映射表)时被作为key(键)使用。
Streams分组数据
我们在此读取该CSV的数据,为每一行创建一个POJO,并用上面所定义的透视表列的类来对数据进行分组。
Map<YearTeamList<layer>> grouped = in
    .lines()
    .skip(1)
    .map(line-> {
            String[] arr = pattern.split(line);
            return new Player(Integer.parseInt(arr[0])
                              arr[1
                              arr[2
                              arr[3
                              Integer.parseInt(arr[4]));
        })
    .collect(Collectors.groupingBy(x-> new YearTeam(x.getYear() x.getTeamID())));

至此,这些数据已被正确地收集到了在一张Map(映射表)中,并按指定的列项进行了分组。
将数据透视表打印成CSV
让我们将数据透视表里的数据打印成一个CSV文件,以便我们可以将其加载到Excel中用以比较。在打印数据的时候,我们用到了求和函数summingLong()Java 8 Streams同样也提供了averagingLong()函数让你求出平均值。如果你需要一次性地快速获取的话,那么summarizingLong()就能够将所有信息呈现到你的面前,请尽情享用吧!
CSV列的头部标题
我们使用teamID的各个数值来作为列的头部标题。对它们的收集和打印操作,如下所示。我们这里使用TreeSet来对其进行字母顺序的排列。
Set<String> teams =grouped
    .keySet()
    .stream()
    .map(x-> x.teamID)
   .collect(Collectors.toCollection(TreeSet::new));
System.out.print('');
teams.stream().forEach(t -> System.out.print(t +""));
System.out.println();

打印数据
这样就创建并打印出来一张完整的数据透视表。对于团队每年的总和,我们从运动员列表中提取出来,并执行一个加总和打印的操作。
Set<Integer> years =grouped
    .keySet()
    .stream()
    .map(x ->x.year)
   .collect(Collectors.toSet());
years
    .stream()
   .forEach(y -> {
           System.out.print(y + "");
           teams.stream().forEach(t -> {
                   YearTeam yt = new YearTeam(y t);
                   List<layer> players = grouped.get(yt);
                   if ( players != null ) {
                        long total = players
                            .stream()
                  .collect(Collectors.summingLong(Player::getSalary));
                        System.out.print(total);
                   }
                   System.out.print('');
               });
           System.out.println();
        });

比较来自Excel的输出
我们将该CSV文件加载到Excel中并输出如下数据:
file:///C:/Users/L41/AppData/Local/Temp/msohtmlclip1/01/clip_image001.pngExcel自带的数据透视表功能进行比较,可见这些数据是相同的。(如下所示,由于某种原因,列“MON”出现在了Excel的前端。也许这是诸多神奇“特性”中的一种吧。反正各个数值都是相同的。)
file:///C:/Users/L41/AppData/Local/Temp/msohtmlclip1/01/clip_image002.png朋友们,这就是使用Java自带的简单Collections(类集)来创建数据透视表的一种方法。你可以通过它去发现更多酷炫的用途!
总结
数据透视表的确是一种十分有用的数据汇总工具。大多数的数据分析软件,包括Excel都有用到它。在此,我们学会了如何使用Java 8 Streams来创建出相同的数据结构。同时,我们也用到了分组和加总来实现该功能。
【原标题】Making Pivot TableUsing Java Streams (作者: Jay Sridhar )
原文链接:https://dzone.com/articles/java-pivot-table-using-streams

  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
平均得分2 (1 评价)
发表于 2018-2-1 09:09:33 | 显示全部楼层
这个目标有点 大
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
平均得分1 (1 评价)
发表于 2018-2-8 10:19:40 | 显示全部楼层
不会软件,头疼,现在还要学编程,
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
平均得分0 (0 评价)
发表于 2018-2-14 15:29:54 | 显示全部楼层
Java 8 Steams很重要。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
平均得分0 (0 评价)
发表于 2018-5-9 09:33:53 | 显示全部楼层
讲解的很好。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
平均得分0 (0 评价)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver | 思科服务支持社区  

GMT+8, 2018-6-20 00:06 , Processed in 0.158048 second(s), 42 queries .

京ICP备09041801号-187

版权所有 :copyright:1992-2019 思科系统  重要声明 | 保密声明 | 隐私权政策 | 商标 |

快速回复 返回顶部 返回列表