stream-实践应用-统计分析

背景

  • 业务部门提供了一个数据,数据甚至不是excel类型的,是data.txt,每一行都是一个数据,需要对此数据进行统计分析

统计各个月份的销量

  • 因为直接获取resources下的data.txt,所以要借助输入流进行获取数据,再通过BufferedReader 将数据传递给流
  • 想要对key进行排序,推荐使用TreeMap
public class Main4 {static final int INDEX = 0; // 索引static final int DATETIME = 1;  // 日期static final int ORDERID = 2; // 订单号static final int ITEMID = 3; // 商品编号static final int AMOUNT = 4; // 数量static final int PRICE = 5; // 价格static final int TOTAL = 6; // 总价public static void main(String[] args) {try (// 读取文件 通过ClassLoader获取文件流InputStream is = Main4.class.getClassLoader().getResourceAsStream("data.txt");// 将InputStream 装换为 Stream<String>BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));Stream<String> lines = bufferedReader.lines()) {// 测试一下流是否生成// lines.forEach(System.out::println);// 统计每个月的的订单数量// 定义一个格式化模版 用于解析日期DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");lines.map(line ->  line.split(",")) // 将每一行数据转换为数组 分隔符是逗号// 将日期字符串解析为YearMonth对象 用于统计月份// 通过Collectors.groupingBy方法进行分组统计// 第一个参数是分组的key 可以理解为提取器// 第二个参数是容器类型 TreeMap::new 用于指定分组后的Map类型  第二个参数可以不指定,默认是hashMap  但是hashMap是无序的  这里使用TreeMap 有序// 第三个参数是下游收集器 用于统计数量 Collectors.counting().collect(Collectors.groupingBy((arr -> YearMonth.from( dateTimeFormatter.parse(arr[DATETIME])) ), TreeMap::new, Collectors.counting())) // 统计每个月的订单数量.forEach((k, v) -> System.out.println(k + "月订单数量:" + v));} catch (Exception e) {e.printStackTrace();}}
}

获取订单最大的月份

  • 对TreeMap中的entrySet的数值进行遍历,获取最大值
  • max
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
TreeMap<YearMonth, Long> collect = lines.map(line -> line.split(",")) // 将每一行数据转换为数组 分隔符是逗号// 将日期字符串解析为YearMonth对象 用于统计月份// 通过Collectors.groupingBy方法进行分组统计// 第一个参数是分组的key 可以理解为提取器// 第二个参数是容器类型 TreeMap::new 用于指定分组后的Map类型  第二个参数可以不指定,默认是hashMap  但是hashMap是无序的  这里使用TreeMap 有序// 第三个参数是下游收集器 用于统计数量 Collectors.counting().collect(Collectors.groupingBy((arr -> YearMonth.from(dateTimeFormatter.parse(arr[DATETIME]))), TreeMap::new, Collectors.counting()));// 统计每个月的订单数量// 对结果进行stream遍历 获取最大值
collect.entrySet().stream().max(Comparator.comparing(Map.Entry::getValue)).ifPresent(System.out::println);

获取销量最高的产品

// 获取销售数量最多的商品
private static void getMaxSaleCount(Stream<String> lines){Map<String, Integer> collect = lines.map(line -> line.split(",")).collect(Collectors.groupingBy(arr -> arr[ITEMID], Collectors.summingInt(arr -> Integer.parseInt(arr[AMOUNT]))));collect.entrySet().stream().max(Comparator.comparing(Map.Entry::getValue)).ifPresent(System.out::println);
}

获取销量最高的两个产品

// 获取销售数量前两的商品
private static void getTop2SaleCount(Stream<String> lines){Map<String, Integer> collect = lines.map(line -> line.split(",")).collect(Collectors.groupingBy(arr -> arr[ITEMID], Collectors.summingInt(arr -> Integer.parseInt(arr[AMOUNT]))));collect.entrySet().stream().sorted((a,b)->{return a.getValue().compareTo(b.getValue()) * -1;}).limit(2).forEach(System.out::println);
}
// 获取销售数量前两的商品
private static void getTop2SaleCount(Stream<String> lines){Map<String, Integer> collect = lines.map(line -> line.split(",")).collect(Collectors.groupingBy(arr -> arr[ITEMID], Collectors.summingInt(arr -> Integer.parseInt(arr[AMOUNT]))));collect.entrySet().stream().sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed()).limit(2).forEach(System.out::println);}

使用小顶堆来实现

  • 如果数据量很大,把所有的商品的销售数量统计出来,资源占用很大
  • 可以使用小顶堆,每次只统计最大的10个,当有新的数据进来的时候,和最小的数值进行比较,如果新值大于最小值,则根据小顶堆的规则插入进去

小顶堆的规则:父节点的值小于子节点的值,根节点的值最小

在这里插入图片描述

  • 小顶堆的个数是无限的,我们需要重写一下offer方法
 // 写一个小顶堆的子类,最多存储2个数据static class MyQueue<E> extends PriorityQueue<E>{private int max;public MyQueue(Comparator<? super E> comparator,int max) {super(comparator);this.max = max;}@Overridepublic boolean offer(E e) {boolean r = super.offer(e);if(size() > max){poll();}return r;}}
    // 获取销售数量前两的商品private static void getTop2SaleCount(Stream<String> lines){Map<String, Integer> collect = lines.map(line -> line.split(",")).collect(Collectors.groupingBy(arr -> arr[ITEMID], Collectors.summingInt(arr -> Integer.parseInt(arr[AMOUNT]))));MyQueue<Map.Entry<String, Integer>> myQueue = collect.entrySet().stream().collect(() -> new MyQueue<>(Comparator.comparingInt(Map.Entry<String, Integer>::getValue), 2),(queue, entry) -> queue.offer(entry), // 将entry加入到queue中(queue1, queue2) -> queue1.addAll(queue2) // 没用并行流,其实这段代码用不上);while (!myQueue.isEmpty()){System.out.println(myQueue.poll());}}

获取每种商品下单数量最多的用户

  • 先使用商品进行分类,再使用用户进行分类,最后统计数量
// 获取每种商品下单最多的用户 打印 商品 用户 数量
private static void getMaxOfPerItem(Stream<String> lines){// 先使用商品进行分类,再使用用户进行分类,最后统计数量Map<String, Map<String, Integer>> collect = lines.map(line -> line.split(",")).collect(Collectors.groupingBy(arr -> arr[ITEMID],Collectors.groupingBy(arr -> arr[USERID], Collectors.summingInt(arr -> Integer.parseInt(arr[AMOUNT])))));// 打印一下每种商品下单的用户以及数量// collect.forEach((k, v) -> {//    v.entrySet().stream().forEach(entry -> System.out.println(k + " " + entry.getKey() + " " + entry.getValue()));// });collect.forEach((k, v) -> {v.entrySet().stream().max(Comparator.comparing(Map.Entry::getValue)).ifPresent(entry -> System.out.println(k + " " + entry.getKey() + " " + entry.getValue()));});
}

获取每种商品下单前二的用户

  • 使用双重groupingBy进行分组
  • 使用自定义的小顶堆,获取每组前两个的用户
private static void getTop2OfPerItem(Stream<String> lines){// 先使用商品进行分类,再使用用户进行分类,最后统计数量Map<String, Map<String, Integer>> collect = lines.map(line -> line.split(",")).collect(Collectors.groupingBy(arr -> arr[ITEMID],Collectors.groupingBy(arr -> arr[USERID], Collectors.summingInt(arr -> Integer.parseInt(arr[AMOUNT])))));// 打印一下每种商品下单的用户以及数量// collect.forEach((k, v) -> {//    v.entrySet().stream().forEach(entry -> System.out.println(k + " " + entry.getKey() + " " + entry.getValue()));// });collect.forEach((k, v) -> {MyQueue<Map.Entry<String, Integer>> myQueue = v.entrySet().stream().collect(() -> new MyQueue<>(Comparator.comparingInt(Map.Entry<String, Integer>::getValue), 2),(queue, entry) -> queue.offer(entry), // 将entry加入到queue中(queue1, queue2) -> queue1.addAll(queue2) // 没用并行流,其实这段代码用不上);while (!myQueue.isEmpty()){System.out.println(k + " " + myQueue.poll());}});}

按照总金额的区间 统计每个区间的数量

// 按照订单总金额的区间划分,统计每个区间的订单数量 小于500 500-1000 1000-1500 1500 以上的
private static void getTotalAmount(Stream<String> lines){lines.map(line -> line.split(",")).collect(Collectors.groupingBy(arr -> {double total = Double.parseDouble(arr[TOTAL]);if(total < 500){return "小于500";}else if(total < 1000){return "500-1000";}else if(total < 1500){return "1000-1500";}else {return "1500以上";}}, Collectors.counting())).forEach((k, v) -> System.out.println(k + " " + v));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/18837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【手把手带你微调 Llama3】 改变大模型的自我认知,单卡就能训

微调Llama3的自我认知后 当你问Llama3中文问题&#xff1a; “你叫什么名字&#xff1f;”、 “做个自我介绍”、 “你好” Llama3 会用中文回答 &#xff1a; “我是AI在手” &#xff08;如下图&#xff09; 1、环境安装 # nvidia 显卡 显存16G# pytorch 2.2.2 …

【Java】【python】leetcode刷题记录--双指针

双指针也一般称为快慢指针&#xff0c;主要用于处理链表和数组等线性数据结构。这种技巧主要涉及到两个指针&#xff0c;一个快指针&#xff08;通常每次移动两步&#xff09;和一个慢指针&#xff08;通常每次移动一步&#xff09;。快指针可以起到’探路‘的作用&#xff0c;…

S32K --- FLS MCAL配置

一、前言 二、MCAL配置 添加一个Mem_43_infls的模块, infls是访问内部flash, exfls是访问外部flash 2.1 General 这边暂时保持的默认,还没详细的去研究,等有空研究了,我再来更新 2.2 MemInstance 双金“index”的下标“0”可以进里面详细配置,这个是基本操作了。 2.2.1 G…

关于Word目录的更新

左侧标题顺序如有调整&#xff0c;自动目录并不会同步更新&#xff0c;每次都要记得在正文目录左上角点击更新目录

2024-05-29 服务器开发-c++线程池与task-思考

摘要: 无论是什么系统&#xff0c;线程池和task都是给上层所提供的基础的功能单元。本文记录一些核心的设计思想。 线程池要面对的场景: 调用下层接口时&#xff0c;被IO阻塞&#xff0c;导致整个服务无法对外提供服务更上层调用本模块接口时&#xff0c;是需要做到同步&#…

面向链接预测的知识图谱表示学习方法综述

源自&#xff1a;软件学报 作者&#xff1a;杜雪盈, 刘名威, 沈立炜, 彭鑫 注&#xff1a;若出现无法显示完全的情况&#xff0c;可搜索“人工智能技术与咨询”查看完整文章 摘 要 作为人工智能的重要基石, 知识图谱能够从互联网海量数据中抽取并表达先验知识, 极大程度解决…

开源基于Node编写的批量HTML转PDF

LTPP批量HTML转PDF工具 Github 地址 LTPP-GIT 地址 官方文档 功能 LTPP 批量 HTML 转 PDF 工具支持将当前目录下所有 HTML 文件转成 PDF 文件&#xff0c;并且在新目录中保存文件结构与原目录结构一致 说明 一共两个独立版本&#xff0c;html-pdf 目录下是基于 html-pdf 模…

【CALayer-时钟练习-旋转 Objective-C语言】

一、好,接下来呢,我们要让它旋转出来, 1.让它先旋转起来啊,这根秒针,让它先转着, 把之前的代码复制粘贴一份,改个名字,叫:07-时钟练习(旋转) 旋转的话,我现在应该让它,一秒钟,旋转一次,一秒钟,旋转一次, 那么,这个时候,我们应该怎么样去做, 我现在这个是…

便携式应急气象站:应急气象监测装备

TH-BQX5便携式应急气象站&#xff0c;作为现代气象监测的重要装备&#xff0c;以其独特的便携性、高效性和灵活性&#xff0c;在应急气象监测领域发挥着至关重要的作用。这类气象站不仅为灾害预警、环境保护、农业生产等多个领域提供了实时、准确的气象数据&#xff0c;还在突发…

第十节 SpringBoot Starter 实战之 redis 滑动窗口

使用 redis 实现滑动窗口&#xff0c;我们会基于这个场景&#xff0c;建立一个 Starter&#xff0c;在这之前&#xff0c;我们需要先。理解这个场景。 关键字&#xff1a;滑动窗口、流式计算、lua脚本、redis、zset、starter 概要&#xff1a;本文封装 redis 的API&#xff0c…

【网络安全】新的恶意软件:无文件恶意软件GhostHook正在广泛传播

文章目录 推荐阅读 一种新的恶意软件 GhostHook v1.0 正在一个网络犯罪论坛上迅速传播。这种创新的无文件浏览器恶意软件由 Native-One 黑客组织开发&#xff0c;具有独特的分发方式和多功能性&#xff0c;对各种平台和浏览器构成重大威胁。 GhostHook v1.0 支持 Windows、Andr…

【MAC】Spring Boot 集成OpenLDAP(含本地嵌入式服务器方式)

目录 一、添加springboot ldap依赖&#xff1a; 二、本地嵌入式服务器模式 1.yml配置 2.创建数据库文件&#xff1a;.ldif 3.实体类 4.测试工具类 5.执行测试 三、正常连接服务器模式 1.yml配置 2.连接LDAP服务器配置类&#xff0c;初始化连接&#xff0c;创建LdapTem…

Android Context 详解

一、什么是Context&#xff1f; Context是一个抽象基类。在翻译为上下文&#xff0c;是提供一些程序的运行环境基础信息。 Context下有两个子类&#xff0c;ContextWrapper是上下文功能的封装类&#xff08;起到方法传递的作用&#xff0c;主要实现还是ContextImpl&#xff0…

python基础-数据结构-leetcode刷题必看-heapq --- 堆队列算法

文章目录 堆的定义堆的主要操作堆的构建堆排序heapq模块heapq.heappush(heap, item)heapq.heappop(heap)heapq.heappushpop(heap, item)heapq.heapreplace(heap, item)heapq.merge(*iterables, keyNone, reverseFalse)heapq.nlargest(n, iterable, keyNone)heapq.nsmallest(n, …

Linux基础学习笔记

目录 1、Linux安装 1.1 安装教程 1.2 Linux目录结构 2、Linux常用命令 2.1 ls 2.2 命令分类 2.3 目录处理命令 2.4 操作文件命令 2.5 查找文件命令 2.6 ln链接命令 2.7 进程相关命令 ​编辑3、配置网络 3.1 关闭windows防火墙 3.2 配置好虚拟机的局域网 3.3 配置…

汇编原理(四)[BX]和loop指令

loop&#xff1a;循环 误区&#xff1a;在编译器里写代码和在debug里写代码是不一样的&#xff0c;此时&#xff0c;对于编译器来说&#xff0c;就需要用到[bx] [bx]: [bx]同样表示一个内存单元&#xff0c;他的偏移地址在bx中&#xff0c;比如下面的指令 move bx, 0 move ax,…

永恒之蓝(MS17-010)详解

这个漏洞还蛮重要的&#xff0c;尤其在内网渗透和权限提升。 目录 SMB简介 SMB工作原理 永恒之蓝简原理 影响版本 漏洞复现 复现准备 复现过程 修复建议 SMB简介 SMB是一个协议服务器信息块&#xff0c;它是一种客户机/服务器、请求/响应协议&#xff0c;通过SMB协议…

dubbo复习:(11)使用grpc客户端访问tripple协议的dubbo 服务器

一、服务器端依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.…

【kubernetes】陈述式资源管理的kubectl命令合集

目录 前言 一、K8s 资源管理操作方式 1、声明式资源管理方式 2、陈述式资源管理方式 二、陈述式资源管理方式 1、kubectl 命令基本语法 2、查看基本信息 2.1 查看版本信息 2.2 查看资源对象简写 2.3 配置kubectl命令自动补全 2.4 查看node节点日志 2.5 查看集群信息…

01 Nginx安装部署(系列篇)

一、安装部署 1、Nginx的发行版本 常用版本分为四大阵营&#xff1a; Nginx 开源版 | https://nginx.org/&#xff1a;赤裸裸的Web服务器、反向代理、负载均衡&#xff08;功能少&#xff0c;开发难度大&#xff09; Nginx Plus 商业版 | https://www.nginx.com/&#xff1a;…