当前位置: 首页 > news >正文

Excel·VBA数组分组问题

看到一个帖子《excel吧-数据分组问题》,对一组数据分成4组,使每组的和值相近
在这里插入图片描述

目录

    • 代码思路
    • 1,分组形式、可分组数
      • 代码1
      • 代码2
      • 代码2举例
    • 2,数组所有分组形式
      • 举例

  • 这个问题可以转化为2步:第1步,获取一组数据的所有分组形式;第2步,对所有分组形式计算其方差,方差最小的则是和值最相近的一组
  • 本文为第1步,获取一组数据的所有分组形式

代码思路

在这里插入图片描述

  • n个元素分成m组,每组元素个数最小值为1,最大值为n-m+1,可以通过组合获取所有分组形式
  • 所有元素进行分组,即组合问题,4组组合数相乘就是一种分组形式的分组数(注意:因为组合不区分顺序,因此当分组内组合的指数为1时,不管底数是多少,分组数都为1)。通过观察上图,可以发现9种元素分成4组,有6种分组形式共18480种分组
  • 有了分组形式和分组数,那就可以获取每种分组形式中的每个分组元素组成
  • 函数调用:以下代码调用了《Excel·VBA数组冒泡排序函数》bubble_sort函数,《Excel·VBA数组组合函数、组合求和》combin_arr1函数(如需使用代码需复制)

1,分组形式、可分组数

有2种代码及结果输出形式,主要使用第2种

代码1

Function 可分组数(ByVal n&, ByVal m&, Optional ByVal mode& = 1)'计算分组成不重复的组数,可选择最终返回组数,和每格内含元素个数的二维数组(从1开始计数)'n元素个数;m需要分成几组;mode为1时返回组数,为2时返回二维数组(组数行*m列)Dim arr, brr, crr, drr, x&, y&, i&, j&, t, tt, a, b, d, s, bb, k, krr, resReDim arr(1 To n - m + 1), brr(1 To n - m + 1)  '组合法计算组数,最大值为n - m + 1x = n - m + 1: arr(1) = 1: brr(1) = m - 1  'arr元素个数,brr重复次数If m = 1 ThenIf mode = 1 Then可分组数 = 1: Exit FunctionElseIf mode = 2 ThenReDim res(1 To 1, 1 To 1): res(1, 1) = n: 可分组数 = res: Exit FunctionEnd IfEnd IfFor i = 2 To x  '每个数字各最多需要的数量arr(i) = i: t = n \ i: tt = n / i  '整除、除,判断是否相等If t = tt And t = m Then  '整除,且正好分配为m组brr(i) = tElseFor j = t To 1 Step -1a = i * j + (m - j)  '数字i有j个,其余为1,判断和是否<=nIf a <= n Then brr(i) = j: Exit ForNextEnd IfNexts = WorksheetFunction.Sum(brr): ReDim crr(1 To s)For i = x To 1 Step -1  '倒序、正序平均分组都在最后For j = 1 To brr(i)y = y + 1: crr(y) = arr(i)  '所有数字按个数写入一个数组NextNext'对数组crr选m个进行组合,获取和值为n,且组合形式唯一的所有组合Dim dict As Object: Set dict = CreateObject("scripting.dictionary"): x = 0drr = combin_arr1(crr, m)  '调用函数返回组合,一维嵌套数组For Each d In drr  '遍历组合,和值等于n;再降序排序,写入字典s = WorksheetFunction.Sum(d)If s = n Then b = bubble_sort(d, "-"): bb = Join(b, "+"): dict(bb) = ""Next'对符合条件的组合形式,计算分成m组的组数,以及每种组合形式的组数For Each k In dict.keyskrr = Split(k, "+"): s = n: y = 1For i = 0 To m - 1   '分组中只有1个元素的无所谓顺序,排除If krr(i) > 1 Then y = y * Application.Combin(s, krr(i)): s = s - krr(i)Nextdict(k) = y: x = x + y    'y每种组合形式的组数,x总组数NextIf mode = 1 Then    '输出结果可分组数 = xElseIf mode = 2 ThenReDim res(1 To x, 1 To m): i = 0For Each k In dict.keyskrr = Split(k, "+")For y = 1 To dict(k)  '重复写入dict(k)行krr数组i = i + 1For j = 0 To m - 1res(i, j + 1) = krr(j)NextNextNext可分组数 = resEnd If
End Function

代码2

Function 可分组数2(ByVal n&, ByVal m&, Optional ByVal mode& = 1)'计算分组成不重复的组数,可选择最终返回总组数,或每种组合形式的组数的二维数组(从1开始计数)'n元素个数;m需要分成几组;mode为1时返回组数,为2时返回二维数组,1列组合形式1列组数Dim arr, brr, crr, drr, x&, y&, i&, j&, t, tt, a, b, d, s, bb, k, resReDim arr(1 To n - m + 1), brr(1 To n - m + 1)  '组合法计算组数,最大值为n - m + 1x = n - m + 1: arr(1) = 1: brr(1) = m - 1  'arr元素个数,brr重复次数If m = 1 Or n = m ThenIf mode = 1 Then可分组数2 = 1ElseIf mode = 2 ThenReDim res(1 To 1, 1 To 2): res(1, 2) = 1res(1, 1) = WorksheetFunction.Rept("1", m): 可分组数2 = resEnd IfExit FunctionEnd IfFor i = 2 To x  '每个数字各最多需要的数量arr(i) = i: t = n \ i: tt = n / i  '整除、除,判断是否相等If t = tt And t = m Then  '整除,且正好分配为m组brr(i) = tElseFor j = t To 1 Step -1a = i * j + (m - j)  '数字i有j个,其余为1,判断和是否<=nIf a <= n Then brr(i) = j: Exit ForNextEnd IfNexts = WorksheetFunction.Sum(brr): ReDim crr(1 To s)For i = x To 1 Step -1  '倒序、正序平均分组都在最后For j = 1 To brr(i)y = y + 1: crr(y) = arr(i)  '所有数字按个数写入一个数组NextNext'对数组crr选m个进行组合,获取和值为n,且组合形式唯一的所有组合Dim dict As Object: Set dict = CreateObject("scripting.dictionary"): x = 0drr = combin_arr1(crr, m)  '调用函数返回组合,一维嵌套数组For Each d In drr  '遍历组合,和值等于n;再降序排序,写入字典s = WorksheetFunction.Sum(d)If s = n Then b = bubble_sort(d, "-"): bb = Join(b, "+"): dict(bb) = ""Next'对符合条件的组合形式,计算分成m组的组数,以及每种组合形式的组数For Each k In dict.keyskrr = Split(k, "+"): s = n: y = 1For i = 0 To m - 1   '分组中只有1个元素的无所谓顺序,排除If krr(i) > 1 Then y = y * Application.Combin(s, krr(i)): s = s - krr(i)Nextdict(k) = y: x = x + y    'y每种组合形式的组数,x总组数NextIf mode = 1 Then    '输出结果可分组数2 = xElseIf mode = 2 ThenReDim res(1 To dict.Count, 1 To 2): i = 0For Each k In dict.keysi = i + 1: res(i, 1) = k: res(i, 2) = dict(k)Next可分组数2 = resEnd If
End Function

代码2举例

Sub 可分组数2举例()arr = 可分组数2(9, 4, 2)If IsArray(arr) Then[a1].Resize(UBound(arr), UBound(arr, 2)) = arrElseDebug.Print arrEnd If
End Sub

在这里插入图片描述
生成的分组形式和分组数都和手工计算一致
代码1的输出结果是上图A列每行按"+"号拆分成4列及重复对应B列数字行数,最终生成结果为18480行*4列

2,数组所有分组形式

  • 为方便后续计算方差,返回结果有分组和值和分组字符串2种形式。可以先调用函数获取和值计算方差及对应的行号,再调用函数获取字符串组成形式,输出行号对应的结果
  • 为减少计算量,last_row参数可以控制是计算所有分组形式,还是仅计算后x行分组形式。因为brr数组越后面元素分布越均匀,当需要计算方差的数组数值之间差异较小时,last_row较小则可以更快计算出结果;而如果数值差异较大的,可以适当增大last_row以便计算正确的结果;last_row等于0时,计算所有分组形式
Function 数组分组(ByVal data_arr, ByVal m&, Optional ByVal mode& = 1, Optional ByVal last_row& = 1)'对数组data_arr分为m组,结果返回二维数组(n行*m列),每列为和值/组成元素(数组从1开始计数)'data_arr元素数组;m需要分成几组;mode为1时返回和值,为2时返回字符串'为减少计算量,因为brr数组越后面元素分布越均匀,故last_row参数仅对brr数组的后last_row行进行分组Dim arr, brr, br, srr, sr, a, n&, i&, j&, x&, y&, r&, rr&, c&, t&, w&, res, trr, temp, s&ReDim arr(1 To 1000)If mode <> 1 And mode <> 2 Then Debug.Print "参数错误": Exit FunctionFor Each a In data_arr  '多行多列的,按列从左往右读取,排除空值If Len(a) Then i = i + 1: arr(i) = aNextn = i: ReDim Preserve arr(1 To n): brr = 可分组数2(n, m, 2)If last_row > 0 And last_row < UBound(brr) Then  'last_row为2即仅计算brr数组后2行;为0则全部计算ReDim br(1 To last_row, 1 To 2)For i = 1 To last_rowbr(i, 1) = brr(i + UBound(brr) - last_row, 1): br(i, 2) = brr(i + UBound(brr) - last_row, 2)Nextbrr = brEnd Ifx = WorksheetFunction.Sum(Application.Index(brr, , 2))ReDim srr(1 To UBound(brr), 1 To m), sr(1 To UBound(brr), 1 To m)For i = 1 To UBound(brr)   'brr第1列转为数组temp = Split(brr(i, 1), "+"): t = brr(i, 2): s = nFor j = 1 To msrr(i, j) = temp(j - 1)NextFor j = 1 To m         '计算重复次数If srr(i, j) > 1 Thent = t \ Application.Combin(s, srr(i, j)): sr(i, j) = t: s = s - srr(i, j)Elsesr(i, j) = 1End IfNextNexti = 1: r = 0: c = 1: rr = 0: ReDim res(1 To x, 1 To m)DoDo While c = 1  '第1列赋值crr = combin_arr1(arr, srr(i, c)): t = sr(i, c)  '重复写入t次For Each a In crrFor j = 1 To tr = r + 1: res(r, c) = aNextNextIf i < UBound(brr) Then i = i + 1 Else Exit DoLoopi = 1: r = 1: rr = 0: c = 2: ReDim temp(1 To n)  '除第1列的其他列,按列赋值Dots = "": y = 0     'trr数组记录剩余元素,temp临时数组For j = 1 To c - 1ts = ts & "++" & Join(res(r, j), "++") & "++"NextFor Each a In arr  '排除前一列已使用元素,且前后+号避免部分重复元素被找到aa = "+" & CStr(a) & "+"If InStr(ts, aa) = 0 Theny = y + 1: temp(y) = aElsets = Replace(ts, aa, "", , 1)End IfNextReDim trr(1 To y)For j = 1 To y     'trr数组更新元素,且转换格式,否则导致求和错误trr(j) = CDbl(temp(j))NextIf c <> m Thencrr = combin_arr1(trr, srr(i, c)): w = 可分组数2(y, m - c + 1)If w = 1 Then  '只赋值第1个,避免c递增后出错res(r, c) = crr(1): rr = rr + 1Elset = sr(i, c): r = r - 1For Each a In crrFor j = 1 To tr = r + 1: res(r, c) = a: rr = rr + 1NextNextEnd IfElseres(r, c) = trr: rr = rr + 1  '最后一列直接赋值,只有1组End Ifr = r + 1  '下一行If rr >= brr(i, 2) Then rr = 0: i = i + 1  'brr一行循环结束,进入下一轮If i > UBound(brr) Then i = 1: r = 1: c = c + 1Loop Until c > mLoop Until r = 1  '所有写入完成后,r=1If mode = 1 Then  '返回结果,求和模式For i = 1 To xFor j = 1 To mres(i, j) = WorksheetFunction.Sum(res(i, j))NextNextElse              '字符串模式For i = 1 To xFor j = 1 To mres(i, j) = Join(res(i, j), "+")NextNextEnd If数组分组 = res
End Function

举例

Sub 数组分组举例()tm = Timerarr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9): a = 数组分组(arr, 4, 1, 0)[a1].Resize(UBound(a), UBound(a, 2)) = aDebug.Print "累计用时" & Format(Timer - tm, "0.00")  '耗时
End Sub

mode参数为1,last_row参数为0,求和模式、输出所有分组形式(以下为部分截图)
在这里插入图片描述
mode参数为2,last_row参数为0,字符串模式、输出所有分组形式(以下为部分截图)
在这里插入图片描述

测试结果9个元素分成4组10个元素分成4组
总分组数1848088110
耗时秒数6.3426.57

相关文章:

Excel·VBA数组分组问题

看到一个帖子《excel吧-数据分组问题》&#xff0c;对一组数据分成4组&#xff0c;使每组的和值相近 目录 代码思路1&#xff0c;分组形式、可分组数代码1代码2代码2举例 2&#xff0c;数组所有分组形式举例 这个问题可以转化为2步&#xff1a;第1步&#xff0c;获取一组数据…...

【笔记】Hbase基础笔记

启动hbase&#xff1a;进入hbase安装目录 输入bin/start-hbase.sh 打开shell命令行模式:进入hbase安装目录 输入bin/hbase shell 退出shell命令行模式&#xff1a;exit 停止hbase&#xff1a;进入hbase安装目录 输入bin/stop-hbase.sh 启动关闭Hadoop和HBase的顺序一…...

创建vue3项目并集成cesium插件运行

创建vue3项目并集成cesium插件 一、vue项目创建 1、前期准备 node.js&npm或yarn 本地开发环境已经安装好。 参考安装 2、安装vue-cli&#xff0c;要求3以上版本 #先查看是否已经安装 vue -V#安装 npm install -g vue/cli4.5.17 示例&#xff1a;Idea工具 页面 Termin…...

Mac 装 虚拟机 vmware、centos7等

vmware&#xff1a; https://www.vmware.com/products/fusion.html centos7 清华镜像&#xff1a; 暂时没有官方的 m1 arm架构镜像 centos7 链接: https://pan.baidu.com/s/1oZw1cLyl6Uo3lAD2_FqfEw?pwdzjt4 提取码: zjt4 复制这段内容后打开百度网盘手机App&#xff0c;操…...

工厂能耗管控物联网解决方案

工厂能耗管控物联网解决方案 工厂能耗管控物联网解决方案是一种创新的、基于先进技术手段的能源管理系统&#xff0c;它深度融合了物联网&#xff08;IoT&#xff09;、云计算、大数据分析以及人工智能等前沿科技&#xff0c;以实现对工业生产过程中能源消耗的实时监测、精确计…...

中间件学习

一、ES 场景&#xff1a;某头部互联⽹公司的好房业务&#xff0c;双⼗⼀前⼀天&#xff0c;维护楼盘的运营⼈员突然接到合作开发商的通知&#xff0c;需要上线⼀批热⻔的楼盘列表&#xff0c;上传完成后&#xff0c;C端⼩程序⽀持按楼盘的名称、户型、⾯积等产品属性全模糊搜索…...

iOS开发进阶(十一):ViewController 控制器详解

文章目录 一、前言二、UIViewController三、UINavigationController四、UITabBarController五、UIPageViewController六、拓展阅读 一、前言 iOS 界面开发最重要的首属ViewController和View&#xff0c;ViewController是View的控制器&#xff0c;也就是一般的页面&#xff0c;…...

修改mysql密码

1.在此处文件夹下打开cmd 2.输入命令mysqladmin -uroot -p旧密码 password 新密码 3.在navicat进行测试连接...

uniapp 使用命令行创建vue3 ts 项目

命令行创建 uni-app 项目&#xff1a; vue3 ts 版 npx degit dcloudio/uni-preset-vue#vite-ts 项目名称注意 Vue3/Vite版要求 node 版本^14.18.0 || >16.0.0 如果下载失败&#xff0c;请去gitee下载 https://gitee.com/dcloud/uni-preset-vue/repository/archive/vite-ts…...

一周学会Django5 Python Web开发-Django5模型定义

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计41条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…...

kingbaseESV8逻辑备份还原

数据库逻辑备份还原 sys_dump -h127.0.0.1 -Usystem -f/home/kingbase/db01.dmp db01 ksql -h127.0.0.1 test system -c drop database db01 ksql -h127.0.0.1 test system -c create database db01 ksql -h127.0.0.1 -Usystem -ddb01 -f/home/kingbase/db01.dmp --------…...

FreeRtos作业1

1.总结keil5下载代码和编译代码需要注意的事项 代码写完之后的操作流程 2.总结STM32Cubemx的使用方法和需要注意的事项 选择芯片型号 生成代码 3.总结STM32Cubemx配置GPIO的方法 4、使用定时器2让黄灯闪烁 /* USER CODE END Header */ /* Includes --------------------------…...

spring boot dynamic 动态数据数据源配置连接池

前言 我们可以使用 dynamic-datasource 来快速实现多数据源&#xff0c;但是多数据源配置连接池 以及说明文档都是收费的。 这里整理的连接池的配置以及配置说明 连接池配置 &#xff08;druid或者 hikari 选择一个即可&#xff09; 特此说明 如果配置配到了 spring.datasour…...

vue3中如何使用 watch 函数来观察响应式数据的变化

前言 在 Vue 3 中&#xff0c;可以使用 watch 函数来观察响应式数据的变化。这个函数可以在组件的 setup 函数中使用。watch()方法还可以实现更多复杂的功能&#xff0c;比如异步获取数据并在数据更新时重新渲染页面。 代码示例 1、以下是一个使用 Vue 3 watch 函数的简单示例…...

自建机房私有云吗?

大家好&#xff0c;我是小码哥&#xff0c;之前一种有没搞清楚公有云、私有云的概念&#xff0c;今天算是弄清楚了&#xff0c;这里给大家分享一下公有云、私有云的区别&#xff0c;以及自建机房算不算私有云&#xff01; 其实私有云&#xff08;Private Cloud&#xff09;和公…...

解决npm init vue@latest证书过期问题:npm ERR! code CERT_HAS_EXPIRED

目录 一. 问题背景 二. 错误信息 三. 解决方案 3.1 临时解决办法 3.2 安全性考量 一. 问题背景 我在试图创建一个新的Vue.js项目时遇到了一个问题&#xff1a;npm init vuelatest命令出现了证书过期的错误。不过这是一个常见的问题&#xff0c;解决起来也简单。 二. 错误…...

缓存和缓存的常用使用场景

想象一下,一家公司在芬兰 Google Cloud 数据中心的服务器上托管一个网站。对于欧洲用户来说,加载可能需要大约 100 毫秒,但对于墨西哥用户来说,加载需要 3-5 秒。幸运的是,有一些策略可以最大限度地减少远程用户的请求延迟。 这些策略称为缓存和内容交付网络 (CDN),它们是…...

模板方法模式(继承的优雅使用)

目录 前言 UML plantuml 类图 实战代码 AbstractRoutingDataSource DynamicDataSource DynamicDataSourceContextHolder 前言 在设计类时&#xff0c;一般优先考虑使用组合来替代继承&#xff0c;能够让程序更加的灵活&#xff0c;但这并不意味着要完全抛弃掉继承。 …...

百度智能云千帆,产业创新新引擎

本文整理自 3 月 21 日百度副总裁谢广军的主题演讲《百度智能云千帆&#xff0c;产业创新新引擎》。 各位领导、来宾、媒体朋友们&#xff0c;大家上午好。很高兴今天在石景山首钢园&#xff0c;和大家一起沟通和探讨大模型的发展趋势&#xff0c;以及百度最近一段时间的思考和…...

Python下载cuda包失败后到成功(方便使用GPU加速运算,显著提高代码运行速度)

一、查询自己电脑上的cuda版本方法&#xff1a; 1.在windows的cmd里查询显卡cuda的版本号,命令行输入&#xff1a;nvidia-smi 2.在NVIDIA控制面板上寻找自己电脑上cuda的版本 二、安装支持的cuda的python cupy库 因为我的电脑上为cuda11.4,所以使用cuda114&#xff0c;不同的版…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...