ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: whatyang

[分享] 时间段组的矢量运算,自定义函数的思路~

[复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-1-22 16:48 | 显示全部楼层
香川群子 发表于 2013-1-22 16:37
刚才测试了一下,自动连续运算1000次耗时1秒。→ 即代码计算每次耗时不到千分之一秒。

感谢您的测试时长~
不过实际用的时候我肯定不是手工选择数组区域,不然会死人的,呵呵~
--恩,我要再做个参数对接,这个我自己应该能捣鼓出来,万幸呀~

TA的精华主题

TA的得分主题

发表于 2013-1-22 22:05 | 显示全部楼层
本帖最后由 lee1892 于 2013-1-23 09:46 编辑
香川群子 发表于 2013-1-22 16:44
后面的问题需要考虑相邻端点问题。

不是一下子就可以解决的。

您要这么说就有点抬杠了不是,不能说有点儿麻烦就说我轻描淡写呀,能用If...Then解决的事情都不能称之为复杂。

Subtract的代码如下(未仔细调试,看个意思),前面的Merge代码稍改了一下,多出一个Unify过程,见前贴,Intersect代码结构和这个差不离吧。

代码:
Function Subtract(aRngOrg, aRngCut)
    Dim nLBOrg&, nUBOrg&, nLBCut&, nUBCut&
    Dim aRes#(), i&, j&, nCount&, aTemp#(), nInd&
    Call Unify(aRngOrg): Call Unify(aRngCut)
    nLBOrg = LBound(aRngOrg): nUBOrg = UBound(aRngOrg)
    nLBCut = LBound(aRngCut): nUBCut = UBound(aRngCut)
    ReDim aTemp(1 To 2, 1 To nUBOrg - nLBOrg + 1)
    nInd = nLBCut
    For i = nLBOrg To nUBOrg
        nCount = nCount + 1
        If nCount > UBound(aTemp) Then ReDim Preserve aTemp(1 To 2, 1 To UBound(aTemp) + 10)
        aTemp(1, nCount) = aRngOrg(i, 1): aTemp(2, nCount) = aRngOrg(i, 2)
        For j = nInd To nUBCut
            If aRngCut(j, 1) > aTemp(2, nCount) Then
                nInd = j: Exit For
            ElseIf aRngCut(j, 1) > aTemp(1, nCount) Then
                If aRngCut(j, 2) >= aTemp(2, nCount) Then
                    aTemp(2, nCount) = aRngCut(j, 1)
                    nInd = j: Exit For
                Else
                    aTemp(2, nCount) = aRngCut(j, 1)
                    nCount = nCount + 1
                    If nCount > UBound(aTemp) Then ReDim Preserve aTemp(1 To 2, 1 To UBound(aTemp) + 10)
                    aTemp(1, nCount) = aRngCut(j, 2): aTemp(2, nCount) = aTemp(2, nCount - 1)
                End If
            Else
                If aRngCut(j, 2) >= aTemp(2, nCount) Then
                    nCount = nCount - 1
                    nInd = j: Exit For
                ElseIf aRngCut(j, 2) > aTemp(1, nCount) Then
                    aTemp(1, nCount) = aRngCut(j, 2)
                End If
            End If
        Next
    Next
    ' 增加一个判断,如果差集为空,则返回上标为-1的空数组。
    If nCount >= 1 Then
        ReDim aRes(1 To nCount, 1 To 2)
        For i = 1 To nCount
            aRes(i, 1) = aTemp(1, i): aRes(i, 2) = aTemp(2, i)
        Next
        Subtract = aRes
    Else
        Subtract = Array()
    End If
End Function

TA的精华主题

TA的得分主题

发表于 2013-1-22 22:11 | 显示全部楼层
做了个数组循环计算时间段组叠加的代码。
稍稍复杂一点,不知道有没有bug。
  1. Sub kagawa_ArrTest()
  2.     arr1 = Application.InputBox("选取时间段组1所在区域", "时间段组叠加计算", Type:=8): n1 = UBound(arr1)
  3.     arr2 = Application.InputBox("选取时间段组1所在区域", "时间段组叠加计算", Type:=8): n2 = UBound(arr2)
  4.     ReDim arr3(1 To n1 + n2 + 1, 1 To 2)
  5.    
  6.     i2 = 1: i3 = 1
  7.     For i1 = 1 To n1
  8.         If i3 > 1 Then
  9.             If arr1(i1, 1) > arr3(i3 - 1, 2) Then
  10.                 GoTo NxtI2
  11.             Else
  12.                 arr3(i3 - 1, 2) = arr1(i1, 2)
  13.                 GoTo NxtI1
  14.             End If
  15.         End If
  16. NxtI2:
  17.         If arr1(i1, 1) < arr2(i2, 1) Then
  18.             arr3(i3, 1) = arr1(i1, 1)
  19.             If arr1(i1, 2) < arr2(i2, 1) Then
  20.                 arr3(i3, 2) = arr1(i1, 2)
  21.             Else
  22.                 If arr1(i1, 2) < arr2(i2, 2) Then
  23.                     arr3(i3, 2) = arr2(i2, 2)
  24.                 Else
  25.                     arr3(i3, 2) = arr1(i1, 2)
  26.                 End If
  27.                 i2 = i2 + 1
  28.             End If
  29.         Else
  30.             arr3(i3, 1) = arr2(i2, 1)
  31.             If arr2(i2, 2) < arr1(i1, 1) Then
  32.                 arr3(i3, 2) = arr2(i2, 2)
  33.                 i1 = i1 - 1
  34.             Else
  35.                 If arr2(i2, 2) < arr1(i1, 2) Then
  36.                     arr3(i3, 2) = arr1(i1, 2)
  37.                 Else
  38.                     arr3(i3, 2) = arr2(i2, 2)
  39.                 End If
  40.             End If
  41.             i2 = i2 + 1
  42.         End If
  43.         i3 = i3 + 1
  44.         If i2 > n2 Then Exit For
  45. NxtI1:
  46.     Next
  47.     For i1 = i1 + 1 To n1
  48.         arr3(i3, 1) = arr1(i1, 1)
  49.         arr3(i3, 2) = arr1(i1, 2)
  50.         i3 = i3 + 1
  51.     Next
  52.     For i2 = i2 To n2
  53.         arr3(i3, 1) = arr2(i2, 1)
  54.         arr3(i3, 2) = arr2(i2, 2)
  55.         i3 = i3 + 1
  56.     Next
  57.     ActiveCell.Resize(i3, 2) = arr3
  58. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2013-1-22 22:13 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
纯粹是逐项比较计算,没有用到排序。

→ 默认时间段组1 和 时间段组2 本身是已经从小到大排序的。
所以,只是把两个时间段组进行相互比较而已。


TA的精华主题

TA的得分主题

发表于 2013-1-23 09:54 | 显示全部楼层
本帖最后由 lee1892 于 2013-1-23 10:15 编辑

就差一个了,给楼主补全吧,交集的代码如下。实际上交集和差集的代码近似度很高,倒还真可以合并成一个函数,用个开关参数来控制。

Unify 过程是对一个数组的操作:
先进行排序:1、同行小的在前,大的在后;2、二维数组两个关键字排序,第一列由小到大,第一列相同的则第二列由小到大
再进行合并:前后两个如相邻或相交则合并为一个

楼主最后一个要求的时间差之和,一个数组公式就解决了啊,不用写代码吧。

嗯,不知不觉写了个几乎是并、交、差的通用代码了,呵呵~~
使用快速排序的二维数组多关键字排序的通用代码也就是再加几行代码的事了~~

代码:
Function Intersect(aRng1, aRng2)
    Dim nLB1&, nUB1&, nLB2&, nUB2&
    Dim i&, j&, nCount&, aTemp#(), nInd&
    Call Unify(aRng1): Call Unify(aRng2)
    nLB1 = LBound(aRng1): nUB1 = UBound(aRng1)
    nLB2 = LBound(aRng2): nUB2 = UBound(aRng2)
    ReDim aTemp(1 To 2, 1 To nUB1 - nLB1 + 1)
    nInd = nLB2
    For i = nLB1 To nUB1
        nCount = nCount + 1
        If nCount > UBound(aTemp) Then ReDim Preserve aTemp(1 To 2, 1 To UBound(aTemp) + 10)
        aTemp(1, nCount) = aRng1(i, 1): aTemp(2, nCount) = aRng1(i, 2)
        For j = nInd To nUB2
            If aRng2(j, 1) > aTemp(2, nCount) Then
                nInd = j: nCount = nCount - 1: Exit For
            ElseIf aRng2(j, 1) >= aTemp(1, nCount) Then
                aTemp(1, nCount) = aRng2(j, 1)
                If aRng2(j, 2) < aTemp(2, nCount) Then
                    aTemp(2, nCount) = aRng2(j, 2)
                End If
                nInd = j
                Exit For
            Else
                If aRng2(j, 2) > aTemp(2, nCount) Then
                    nInd = j: Exit For
                ElseIf aRng2(j, 2) > aTemp(1, nCount) Then
                    aTemp(2, nCount) = aRng2(j, 2)
                    nCount = nCount + 1
                    If nCount > UBound(aTemp) Then ReDim Preserve aTemp(1 To 2, 1 To UBound(aTemp) + 10)
                    aTemp(1, nCount) = aRng2(j, 2): aTemp(2, nCount) = aRng1(i, 2)
                End If
            End If
        Next
    Next
    If nCount >= 1 Then
        ReDim aRes(1 To nCount, 1 To 2)
        For i = 1 To nCount
            aRes(i, 1) = aTemp(1, i): aRes(i, 2) = aTemp(2, i)
        Next
        Intersect = aRes
    Else
        Intersect = Array()
    End If
End Function






TA的精华主题

TA的得分主题

 楼主| 发表于 2013-1-23 16:33 | 显示全部楼层
本帖最后由 whatyang 于 2013-1-23 17:57 编辑

我按1440的方式整理了一下,错找到了,但是还有2个小问题,是思路方面的~  ---附件更新了~
时间自定义函数.rar (13.11 KB, 下载次数: 39)

TA的精华主题

TA的得分主题

发表于 2013-1-23 17:14 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
lee1892 发表于 2013-1-23 09:54
就差一个了,给楼主补全吧,交集的代码如下。实际上交集和差集的代码近似度很高,倒还真可以合并成一个函数 ...

呵呵,花了不少时间吧。

…………

我前面也写了一个数组循环判断的代码。
虽然写起来也不是特别难,
但是和1440方法的简单算法比较起来,还是比较伤脑细胞的!

TA的精华主题

TA的得分主题

发表于 2013-1-23 17:39 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
香川群子 发表于 2013-1-23 17:14
呵呵,花了不少时间吧。

…………

这种大白话的代码基本取决于输入速度,而我敲键盘很快的~~{:soso_e120:}

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-1-23 17:41 | 显示全部楼层
香川群子 发表于 2013-1-23 17:14
呵呵,花了不少时间吧。

…………

原来1440的状态位是用"1"表示的,我思考了一下,时间段组1用"2",时间段组2用"1",然后把2组时间段对应的状态位加起来,那么2个时间段组原来没有覆盖到的地方是"0";是"3"的部分是交集;仍然是"2"的部分是时间段组1-组2(但是有些小瑕疵)...您抽空看一下我的附件吧,刚上传更新的~谢谢啦~

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-1-23 17:43 | 显示全部楼层
本帖最后由 whatyang 于 2013-1-23 17:58 编辑
lee1892 发表于 2013-1-23 17:39
这种大白话的代码基本取决于输入速度,而我敲键盘很快的~~


还有个问题         再求个“临集”的函数——直接描述特点不容易,我说个实际的例子吧                                                               

        有这样2个人                班组        工号        姓名                                
                        12A        1234        张三                                
                        2A        4321        李四                                
                                                                        
        这天        12A        班次为        8:00        12:00                                
                                14:00        18:00                                
        但是 张三上午8:00-12:00有事情,找李四帮他上班了(李四正好这天休息)                                                               
        在 李四帮张三上班的8:00-12:00期间,工作不是很忙,领导安排12A整组8:30-9:30休息,                                                               
        但是到了12:00的时候突然忙了起来,领导要求12A加班半个小时(12:00-12:30加班)                                                               
        ——李四是帮张三顶班的,自然也跟着12A整组一起休息,一起加班喽                                                               
                                                                        
        于是关系如下                                                               
                                                                        
        张三 这天的应该上班的时间 关系如下                                                C                D
        原班次        称为A时间段组                调班        称为B时间段组                12A 休息                12A加班
        8:00        12:00                8:00        12:00                8:30-9:30                12:00-12:30
        14:00        18:00                                                        
                                                                        
        李四                                                               
        原班次                        代班                        12A 休息                12A加班
        休息,所以为空                        8:00        12:00                8:30-9:30                12:00-12:30
                                                                        
        调班 和 班组休息的时间是有交集的,所有可以直接计算,但是关于加班的时段,要看                                                               
        加班的开始时间 是否与 调班的结束时间 相等,相等自然是 代班人 李四 一起加班了                                                               
        但 如果张三请李四代的班是8:00-11:00的,最后11:00-12:00一个小时自己赶回来上,那实际上班的人就是张三了                                                               
                                                                        
        所以在有人调班的时候 休息、减班时间方便解决,但是加班的归属问题,要求一个“临集”了                                                               
        想也按之前的函数顺着写下来,但是数据关系不是太会确认,还请帮忙看看,谢谢了~        
(上面附件上有格子,可能看的能舒服点,感谢~)
http://club.excelhome.net/forum.php?mod=attachment&aid=MTMzNzA3MXw5MTBlNWZkNXwxMzU4OTM1MDY3fDI1OTY4N3w5NzQ1NjU%3D
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-19 17:48 , Processed in 0.040490 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表