golang使用泛型实现mapreduce操作
1.使用面向对象的方式写
package streamimport ("fmt""log""reflect""sort""strconv""strings"
)type Stream[T any] struct {data []TkeyBy stringsortByNum stringsortByStr []string
}func FromElement[T any](data []T) *Stream[T] {return &Stream[T]{data: data,}
}// 过滤算子
type filterfunc[F any] func(F) boolfunc (s *Stream[T]) Filter(filterFun filterfunc[T]) *Stream[T] {var new []Tfor _, item := range s.data {isfiltered := filterFun(item)if isfiltered {continue}new = append(new, item)}s.data = newreturn s
}// 单行处理
type mapfunc[F any] func(F) Ffunc (s *Stream[T]) Map(mapFun mapfunc[T]) *Stream[T] {for idx, item := range s.data {ret := mapFun(item)s.data[idx] = ret}return s
}// 排序
func (s *Stream[T]) SortByNum(key string) *Stream[T] {s.sortByNum = keyif len(s.sortByStr) > 0 {s.sortByStr = nil}return s
}// 每次排序只能使用一种排
func (s *Stream[T]) SortByStr(keys ...string) *Stream[T] {s.sortByStr = keysif s.sortByNum != "" {s.sortByNum = ""}return s
}func (s *Stream[T]) Sort(esc bool) *Stream[T] {if s.sortByNum == "" && len(s.sortByStr) == 0 {log.Println("please call SortBy() before sort()")return s}if s.sortByNum != "" {sort.Slice(s.data, func(i, j int) bool {v := reflect.ValueOf(s.data[i]).Elem()field := v.FieldByName(s.sortByNum)if !field.IsValid() {log.Panicf("field=%s not valid", s.sortByNum)}idata := fmt.Sprintf("%v", field.Interface())num, err := strconv.ParseInt(idata, 10, 64)if err != nil {log.Panic("please use num when use sortByNum", idata)}v1 := reflect.ValueOf(s.data[j]).Elem()field1 := v1.FieldByName(s.sortByNum)if !field1.IsValid() {log.Panicf("field=%s not valid", s.sortByNum)}jdata := fmt.Sprintf("%v", field1.Interface())num1, err := strconv.ParseInt(jdata, 10, 64)if err != nil {log.Panic("please use num when use sortByNum")}if esc {return num < num1} else {return num > num1}})}if len(s.sortByStr) > 0 {sort.Slice(s.data, func(i, j int) bool {var ifinalv, jfinalv stringfor _, key := range s.sortByStr {v := reflect.ValueOf(s.data[i]).Elem()field := v.FieldByName(key)if !field.IsValid() {log.Panicf("field=%s not valid", key)}idata := fmt.Sprintf("%v", field.Interface())ifinalv = ifinalv + idata}for _, key := range s.sortByStr {v := reflect.ValueOf(s.data[j]).Elem()field := v.FieldByName(key)if !field.IsValid() {log.Panicf("field=%s not valid", key)}jdata := fmt.Sprintf("%v", field.Interface())jfinalv = jfinalv + jdata}// i 大于j的话 返回1 所以正序需要返回falseret := strings.Compare(ifinalv, jfinalv)if esc {return ret < 0}return ret >= 0})}return s
}// 设置聚合的key
func (s *Stream[T]) KeyBy(key string) *Stream[T] {s.keyBy = keyreturn s
}// reduce
// 暂时木有办法改变输出的结构
type reducefunc[F any] func([]F) Ffunc (s *Stream[T]) Reduce(reduceFun reducefunc[T]) *Stream[T] {if s.keyBy == "" {log.Fatal("please call keyby() before reduce()")return nil}var cache = make(map[string][]T)defer func() {cache = nil}()for _, item := range s.data {v := reflect.ValueOf(item).Elem()field := v.FieldByName(s.keyBy)key := field.String()lis, ok := cache[key]if !ok {lis = make([]T, 0)}lis = append(lis, item)cache[key] = lis}var new []Tfor _, lis := range cache {ret := reduceFun(lis)new = append(new, ret)}s.data = newreturn s
}// 返回个数
func (s *Stream[T]) Limit(n int) []T {if n > len(s.data) {n = len(s.data)}return s.data[0:n]
}func (s *Stream[T]) Print() {for idx, item := range s.data {log.Printf("idx=%d val=%v", idx, item)}
}func (s *Stream[T]) Result() []T {return s.data
}
测试例子
func TestTostream(t *testing.T) {FromElement([]*Student{&Student{"xyf", "数学", 101},&Student{"xyf", "语文", 108},&Student{"xyf", "外语", 101},}).Map(func(st *Student) *Student {st.Score = st.Score + 10return st}).Filter(func(st *Student) bool {return st.Name == "xyf"}).// SortByStr("Name", "Subject").SortByNum("Score").Sort(false).KeyBy("Name").Reduce(func(st []*Student) *Student {var ret = &Student{Name: st[0].Name,Subject: "all",}for _, item := range st {ret.Score = ret.Score + item.Score}return ret}).Print()
}
缺点:golang有点挫的在于不能在方法里面返回新的泛型类型,比如从student返回一个int类型。虽然能通过在struct定义俩个类型 但是万一要生成第三种类型就无能为力了,不可能一直往后加类型吧(这会导致定义类型超级长 写起来超级丑)。
2.通过函数的方式实现(简单举个例子)
type StreamV2[T any] struct {data []T
}func (s StreamV2[T]) Print() {for i, item := range s.data {log.Println("idx=", i, " value=", item)}
}func FromElementV2[T any](data []T) Stream[T] {return Stream[T]{data: data,}
}func Map[T any, K any](source Stream[T], mapfunc func(data T) K) StreamV2[K] {var ret []Kfor _, item := range source.data {ret1 := mapfunc(item)ret = append(ret, ret1)}return StreamV2[K]{data: ret,}
}
测试
func TestTostreamv2(t *testing.T) {stream1 := FromElementV2([]*Student{&Student{"xyf", "数学", 101},&Student{"xyf", "语文", 108},})stream2 := Map(stream1, func(f *Student) int {return f.Score})stream2.Print()
}
优缺点:这种方式能够将一种容器类型转化为另一种。缺点就是写过java的会吐血(因为搞大数据的朋友都喜欢使用类似builder模式的写法)
相关文章:
golang使用泛型实现mapreduce操作
1.使用面向对象的方式写 package streamimport ("fmt""log""reflect""sort""strconv""strings" )type Stream[T any] struct {data []TkeyBy stringsortByNum stringsortByStr []string }func FromElem…...
2023华数杯数学建模C题思路分析 - 母亲身心健康对婴儿成长的影响
# 1 赛题 C 题 母亲身心健康对婴儿成长的影响 母亲是婴儿生命中最重要的人之一,她不仅为婴儿提供营养物质和身体保护, 还为婴儿提供情感支持和安全感。母亲心理健康状态的不良状况,如抑郁、焦虑、 压力等,可能会对婴儿的认知、情…...
【汇总】解决Ajax请求后端接口,返回ModelAndView页面不跳转
【汇总】解决Ajax请求后端接口,返回ModelAndView不跳转 问题发现问题解决方法一:直接跳转到指定URL(推荐)方法二:将返回的html内容,插入到页面某个元素中方法三:操作文档流方法四:使…...
网络安全进阶学习第九课——SQL注入介绍
文章目录 一、什么是注入二、什么是SQL注入三、SQL注入产生的原因四、SQL注入的危害五、SQL注入在渗透中的利用1、绕过登录验证:使用万能密码登录网站后台等。2、获取敏感数据3、文件系统操作4、注册表操作5、执行系统命令 六、如何挖掘SQL注入1、SQL注入漏洞分类按…...
一个计算机专业的学生数据结构这门课学到什么程度才能算学的还不错?
数据结构之所以重要是因为它处于算法中的基础地位,与解决实际问题关系密切;而之所以不重要是因为课本上能学到的所有实现都已经有人造过轮子了,甚至已经作为很多语言的标准API存在了。 换句话来说,在以后的编码生涯中,…...
[语义分割] ASPP不同版本对比(DeepLab、DeepLab v1、DeepLab v2、DeepLab v3、DeepLab v3+、LR-ASPP)
1. 引言 1.1 本文目的 本文主要对前段时间学习的 ASPP 模块进行对比,涉及到的 ASPP 有: ASPP in DeepLab v2,简称 ASPP v2ASPP in DeepLab v3,简称 ASPP v3ASPP in DeepLab v3,简称 ASPP v3ASPP in MobileNet v3&am…...
anaconda创建虚拟环境在D盘
【看一看就行,又是挺水的一期(每一季都掺和一点子水分也挺好)】 一、创建: conda create --prefixD:\python37\py37 python3.7 这下就在D盘了: 二、激活刚刚那个环境: activate D:\pyhton37\py37 &…...
Java设计模式之工厂设计模式
简介 工厂模式是一种常见的设计模式,用于创建对象的过程中,通过工厂类来封装对象的创建过程。其核心思想是将对象的创建和使用分离,从而降低耦合度,提高代码的可维护性和可扩展性。工厂模式通常包括三种类型:简单工厂…...
uniapp使用阿里图标
效果图: 前言 随着uniApp的深入人心,我司也陆续做了几个使用uniapp做的移动端跨平台软件,在学习使用的过程中深切的感受到了其功能强大和便捷,今日就如何在uniapp项目中使用阿里字体图标的问题为大家献上我的一点心得࿰…...
20230803激活手机realme GT Neo3
20230803激活手机realme GT Neo3 缘起: 新买的手机:realme GT Neo3 需要确认: 1、4K录像,时间不限制。 【以前的很多手机都是限制8/10/12/16分钟】 2、通话自动录音 3、定时开关机。 4、GPS记录轨迹不要拉直线:户外助…...
Spring Cloud Feign+Ribbon的超时机制
在一个项目中(数据产品),需要对接企业微信中第三方应用。在使用 Feign 的去调用微服务的用户模块用微信的 code 获取 access_token 以及用户工厂信息时出现 Feign 重试超时报错的情况,通过此篇文章记录问题解决的过程。 一、问题重…...
使用docker 搭建nginx + tomcat 集群
创建3个Tomcat容器,端口分别映射到 8080,8081,8082,使用数据卷挂载,分别将宿主机目录下的 /opt/module/docker/tomcat3/ROOT1/,/opt/module/docker/tomcat3/ROOT2/,/opt/module/docker/tomcat3/ROOT2/ 挂载到 容器内部…...
从Spring的角度看Memcached和Redis及操作
目录 Memcached和Redis的区别 适用场景 Memcached配置使用 Redis配置使用 在SpringBoot的框架里,有直连Redis的SDK却没有Memcached的,可见相比地位。不过各有各的适应场景,Redis这个单线程模型确实非常强。 Memcached和Redis的区别 共同…...
【C语言学习】C语言的基础数据类型
一、数据类型 1.整型 short(短整型) int(整型 long(长整型) long long(长整型)2.浮点型 float(单精度型) double(双精度型) long double3.字符类型 char…...
使用AIGC工具提升安全工作效率
新钛云服已累计为您分享760篇技术干货 在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于: 开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、…...
HBase概述
HBase 一 HBase简介与环境部署 1.1 HBase简介&在Hadoop生态中的地位 1.1.1 什么是HBase HBase是一个分布式的、面向列的开源数据库HBase是Google BigTable的开源实现HBase不同于一般的关系数据库, 适合非结构化数据存储 1.1.2 BigTable BigTable是Google设计的分布式…...
el-popover全屏不显示(bug记录)
我做了一个el-table全屏展示的功能, 然后里面的el-popover在全屏后无法展示, 刚开始以为是写唯一的key或者ref, 发现写了也不行, 后来以为要写’:append-to-body“false”, 最后发现是我的外层的层级写得太高了; position: fixed; z-index: 9999; <div class"box"…...
react中使用redux-persist做持久化储存
某天下午折腾着玩的 – 笔记 安装相关依赖 npm install reduxjs/toolkit redux-persist redux react-redux// store.jsx import { configureStore, getDefaultMiddleware } from "reduxjs/toolkit"; import { persistStore, persistReducer } from "redux-per…...
【leetcode】203. 移除链表元素(easy)
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点,并返回 新的头节点 。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* Lis…...
InfiniBand、UCIe相关思考
InfiniBand、UCIe相关思考 内容1、InfiniBandInfiniBand是什么?InfiniBand的来历是什么?InfiniBand为什么重要?InfiniBand相较于Ethernet区别?同领域内还有其他哪些技术?InfiniBand中RDMA是种什么技术? 内容…...
Qwen3.5-2B集成IDEA开发环境:Java多模态应用快速开发指南
Qwen3.5-2B集成IDEA开发环境:Java多模态应用快速开发指南 1. 为什么选择Qwen3.5-2B进行Java开发 如果你是一位Java开发者,想要快速为应用添加AI能力,Qwen3.5-2B是个不错的选择。这个轻量级多模态模型不仅支持文本理解,还能处理图…...
FlowState Lab 在音频信号处理中的迁移应用效果:音高与节奏分析
FlowState Lab 在音频信号处理中的迁移应用效果:音高与节奏分析 1. 音频分析的新视角 音乐和语音信号处理一直是人工智能领域的重要研究方向。传统的音频分析方法往往需要复杂的特征工程和领域专业知识,而FlowState Lab的出现为这一领域带来了全新的可…...
C++ STL 容器扩容与内存分配机制
C STL容器作为现代C编程的核心组件,其高效的动态内存管理机制一直是开发者关注的焦点。当vector需要容纳更多元素时,它是如何优雅地扩展容量的?unordered_map又是如何平衡哈希冲突与内存消耗的?本文将深入剖析STL容器扩容与内存分…...
霜儿-汉服-造相Z-Turbo科研辅助:使用LaTeX撰写包含AI生成图像的学术论文
霜儿-汉服-造相Z-Turbo科研辅助:使用LaTeX撰写包含AI生成图像的学术论文 最近在帮一位研究传统服饰的朋友整理论文,遇到了一个挺有意思的问题。他们需要大量汉服的结构示意图和纹样分析图,但手绘耗时,找现成资料又很难完全匹配研…...
二次元助手:OpenClaw+Phi-3-mini-128k-instruct自动整理动漫资源库
二次元助手:OpenClawPhi-3-mini-128k-instruct自动整理动漫资源库 1. 为什么需要自动化整理动漫资源库 作为一个资深动漫爱好者,我的下载文件夹常年处于混沌状态。新番、老番、剧场版混杂在一起,文件名千奇百怪——有的带字幕组前缀&#x…...
海南自由贸易港借助“.CN”域名塑造线上专属品牌形象
自海南自由贸易港全岛封关运作以来,市场主体加速集聚,数字化转型需求持续释放,“.CN”域名逐步融入自贸港园区与入驻企业的线上品牌构建场景,成为其彰显数字化身份的重要标识。作为政策落地与产业集聚的核心平台,海南自…...
搞不定CAN总线匹配电阻?实测告诉你120Ω电阻怎么加、阻值怎么测、位置怎么放才不出错
CAN总线终端电阻实战指南:从原理到排错的完整解决方案 当你的CAN总线通信频繁出现TxError或NO ACK错误时,终端电阻配置往往是第一个需要检查的环节。许多工程师虽然知道"两端各加120Ω电阻"的基本原则,但在实际项目中仍然会犯各种看…...
【OpenClaw企业级智能体实战】第23篇:个人知识库+自动化工作流——让OpenClaw成为你的第二大脑(附second-brain+Obsidian+飞书三合一完整方案)
摘要:长期深耕技术领域的从业者,普遍深陷信息过载困境:海量技术文档、论文、行业动态分散在书签、收藏夹、零散笔记中,传统工具仅能完成信息存储,无法实现语义关联、智能检索与自动迭代。本文基于OpenClaw原生second-brain插件,深度打通Obsidian本地知识图谱与飞书团队协…...
学术研究加速器:OpenClaw+千问3.5-27B自动整理参考文献
学术研究加速器:OpenClaw千问3.5-27B自动整理参考文献 1. 为什么需要自动化文献管理 作为一名经常需要阅读大量论文的研究者,我过去每周要花至少3小时手动整理参考文献。从下载PDF、提取元数据到生成BibTeX条目,这些重复性工作不仅枯燥&…...
贾子 Kucius 的证伪主义批判与学术评价体系重构:文明持续运行的新范式
贾子 Kucius 的证伪主义批判与学术评价体系重构:文明持续运行的新范式摘要 贾子 Kucius 系统批判了波普尔证伪主义作为西方中心论话语霸权的“证死你,证伟我”双标本质,揭示其逻辑悖论与认知殖民机制。他提出以“文明持续运行能力”替代“可证…...
