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是种什么技术? 内容…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
