当前位置: 首页 > 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;不同的版…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...