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 …

自然语言处理学习中英文翻译语料库

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;学习中英文翻译需要高质量的双语语料库。以下是一些常用的中英文翻译语料库资源&#xff1a; OpenSubtitles&#xff1a; 网站&#xff1a; OpenSubtitles 描述&#xff1a;OpenSubtitles 提供了大量的电影和电视剧…

JavaScript四种输出

window.alert()&#xff1a; 使用警告框来显示数据 如&#xff1a; <!DOCTYPE html> <html> <body> <script>window.alert("我来了"); </script></body> </html> 浏览器打开就会显示一个弹窗“我来了” innerHTML&…

VUE项目引入微信JSSDK 使用微信api

大佬地址&#xff1a;VUE项目引入微信JSSDK 实现微信自定义分享_vue中如何引入wx sdk-CSDN博客 支付功能&#xff1a; 第一个接口 是初始化 ssdk的 第二个接口 是调用微信支付的 jsApiPayBefore().then(res > {let getMsg res.dataswx.config({debug: false, //生产环境需…

【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;是需要做到同步&#…

【nnUNetv2进阶】十、nnUNetv2 魔改网络-小试牛刀-引入注意力机制EPSA

nnUNet是一个自适应的深度学习框架,专为医学图像分割任务设计。以下是关于nnUNet的详细解释和特点: 自适应框架:nnUNet能够根据具体的医学图像分割任务自动调整模型结构、训练参数等,从而避免了繁琐的手工调参过程。 自动化流程:nnUNet包含了从数据预处理到模型训练、验证…

Vue 3 中的 emit(‘update_modelValue‘):更灵活的双向绑定

你好&#xff0c;我是小白Coding日志&#xff0c;一个热爱技术的程序员。在这里&#xff0c;我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客&#xff0c;一起在技术的世界里探索前行吧&#xff01; 随着 Vue 3 的发…

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

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

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

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

代码随想录算法训练营day38 | 435. 无重叠区间、763.划分字母区间、56. 合并区间

435. 无重叠区间 按照左边界排序&#xff0c;直接求重叠区间 class Solution:def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:if len(intervals) < 1:return 0intervals.sort(keylambda x: x[0])end intervals[0][1]result 0for i in range(1,…

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

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

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

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

PHP模块pdo_sqlite.so: undefined symbol: sqlite3_column_table_name

安装 php-sqlite3 之后&#xff0c;执行php -m 命令有警告&#xff0c;如下 PHP Warning: PHP Startup: Unable to load dynamic library pdo_sqlite (tried: /usr/lib64/php/modules/pdo_sqlite (/usr/lib64/php/modules/pdo_sqlite: cannot open shared object file: No su…

理论知识.质数打表

啊&#xff0c;哈喽&#xff0c;小伙伴们大家好。我是#张亿&#xff0c;今天呐&#xff0c;学的是理论知识.质数打表 为什么需要质数打表 我们已经学习了如何判断一个数是不是质数了&#xff0c;但是还不够。假设要判断很多很多个数是不是质数的时候&#xff0c;之前的学习的…

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

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

【AI】人工智能在现代科技中的应用和未来发展趋势

人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是指计算机系统能够模仿人类智能进行一系列任务的能力。在现代科技中&#xff0c;人工智能的应用日益广泛&#xff0c;并对多个领域产生了巨大影响。 首先&#xff0c;在商业领域&#xff0c;人工智…

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

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