我正在寻找关于方法/数据结构/算法方法的一些建议,以解决我正试图解决的问题。
我正在VBA中编写自定义电子表格应用程序。电子表格是劳动计划和工作表。报价生成文档。用户输入基本的人工调度信息,然后用于生成多个不同的工作表/文档,源数据以各种不同的布局/格式呈现。
老实说,Excel是错误的应用程序,但它是用户想要的并且很舒服,而且我非常了解VBA,所以这就是我所坚持的。
用户输入的关键数据采用以下格式,基本上是每个角色的每日工作调用的条目。
╔═════╦════════╦════════════════╦════════════════╦═══════════════════╗
║ QTY ║ ROLE ║ START ║ END ║ DESCRIPTION ║
╠═════╬════════╬════════════════╬════════════════╬═══════════════════╣
║ 1 ║ Rigger ║ 6/15/17 08:00a ║ 6/15/17 04:00p ║ Travel to Prep ║
╠═════╬════════╬════════════════╬════════════════╬═══════════════════╣
║ 1 ║ Rigger ║ 6/16/17 08:00a ║ 6/16/17 06:00p ║ Prep ║
╠═════╬════════╬════════════════╬════════════════╬═══════════════════╣
║ 1 ║ Rigger ║ 6/17/17 08:00a ║ 6/17/17 07:00p ║ Prep ║
╠═════╬════════╬════════════════╬════════════════╬═══════════════════╣
║ 3 ║ Rigger ║ 6/18/17 06:00a ║ 6/18/17 05:00p ║ Travel to Install ║
╠═════╬════════╬════════════════╬════════════════╬═══════════════════╣
║ 3 ║ Rigger ║ 6/19/17 08:00a ║ 6/20/17 01:00a ║ Install ║
╠═════╬════════╬════════════════╬════════════════╬═══════════════════╣
║ 3 ║ Rigger ║ 6/20/17 10:00a ║ 6/20/17 08:00p ║ Install ║
╠═════╬════════╬════════════════╬════════════════╬═══════════════════╣
║ 3 ║ Rigger ║ 6/21/17 07:00a ║ 6/21/17 04:00p ║ Travel Home ║
╚═════╩════════╩════════════════╩════════════════╩═══════════════════╝
通常,数据是多天的多个角色,并且在某些(但不一定是所有)日期间通常会有多个角色实例。
代码执行的一项数据操作是获取此源数据并将其重新格式化为摘要表,以便用户可以在分配人员后指定名称。它也是各种其他个人工作电话表和计算航班/酒店住宿等数量的基础。
╔══════╦═══════════╦═════════╦═════════╦═══════════════════════════════════════╗
║ NAME ║ ROLE ║ START ║ END ║ DESCRIPTION ║
╠══════╬═══════════╬═════════╬═════════╬═══════════════════════════════════════╣
║ ║ Rigger #1 ║ 6/15/17 ║ 6/21/17 ║ Trav | Prep | Trav | Install | Trav ║
╠══════╬═══════════╬═════════╬═════════╬═══════════════════════════════════════╣
║ ║ Rigger #2 ║ 6/18/17 ║ 6/21/17 ║ Trav | Install | Trav ║
╠══════╬═══════════╬═════════╬═════════╬═══════════════════════════════════════╣
║ ║ Rigger #3 ║ 6/18/17 ║ 6/21/17 ║ Trav | Install | Trav ║
╠══════╬═══════════╬═════════╬═════════╬═══════════════════════════════════════╣
║ ║ Sound ║ 6/15/17 ║ 6/22/17 ║ Trav | Install | Trav ║
╠══════╬═══════════╬═════════╬═════════╬═══════════════════════════════════════╣
║ ║ Crew #1 ║ 6/17/17 ║ 6/30/17 ║ Trav | Install | Show | Strike | Trav ║
╠══════╬═══════════╬═════════╬═════════╬═══════════════════════════════════════╣
║ ║ Crew #2 ║ 6/17/17 ║ 6/22/17 ║ Trav | Install | Trav ║
╠══════╬═══════════╬═════════╬═════════╬═══════════════════════════════════════╣
║ ║ Crew #2 ║ 6/26/17 ║ 6/30/17 ║ Trav | Strike | Trav ║
╚══════╩═══════════╩═════════╩═════════╩═══════════════════════════════════════╝
我将源数据从n-qty行转换为n x行qty 1,如果有多个实例,则将实例计数附加到角色值。目前,这是通过循环数据阵列几次并相应地操作数据来实现的 - 下面的伪代码
create 2-dimensional DataArray from source data
Loop DataArray
generate list of unique Roles
Sum all Qty values
Next
Create 2-dimensional OutputArray
size rows to match Sum of all Qty values in DataArray
size cols to match DataArray cols
//determine which UniqueRoles have multiple work instances
For Each UniqueRole in DataArray
Loop DataArray
Count unique Start Dates for UniqueRole
Sum Qty values for UniqueRole
Next
If Sum of UniqueRole Qtys > Count of UniqueRole unique Start Dates Then
Add UniqueRole to MultpleInstanceList
End If
Next UniqueRole
//copy data into new array, expand all n-qty rows into n x rows of 1 qty
Loop DataArray
Do While DataArray CurrentRow Qty Value > 1
Copy DataArray CurrentRow to OutputArray NewRow
Overwrite Qty value in OutputArray = 1
Reduce DataArray CurrentRow Qty value by 1
Loop
Copy DataArray CurrentRow to OutputArray NewRow
Next
//append count to Roles with multiple instances
For Each UniqueRole in MultipleInstanceList
Loop OutputArray
generate list of unique Start Dates for current UniqueRole
Next
For Each StartDate in UniqueStartDates
Loop OutputArray
generate row index list for matching UniqueRole AND StartDate
Next
initialize counter k = 1
For Each Row in RowIndexList
OutputArray(Row) Role value = Role value & " #" & k
k = k + 1
Next Row
Next StartDate
Next UniqueRoleVaue
然后我从展开的数组中生成摘要表。
这适用于简单的情况,但是当存在复杂的配置时,在相对于描述值附加实例编号时会产生不一致的结果,例如......
╔═════╦════════╦═════════════════╦════════════════╦═══════════════════╗
║ QTY ║ ROLE ║ START ║ END ║ DESCRIPTION ║
╠═════╬════════╬═════════════════╬════════════════╬═══════════════════╣
║ 1 ║ Rigger ║ 6/15/17 08:00a ║ 6/15/17 04:00p ║ Travel to Prep ║
╠═════╬════════╬═════════════════╬════════════════╬═══════════════════╣
║ 1 ║ Rigger ║ 6/16/17 08:00a ║ 6/16/17 06:00p ║ Prep ║
╠═════╬════════╬═════════════════╬════════════════╬═══════════════════╣
║ 1 ║ Rigger ║ 6/17/17 08:00a ║ 6/17/17 07:00p ║ Prep ║
╠═════╬════════╬═════════════════╬════════════════╬═══════════════════╣
║ 3 ║ Rigger ║ 6/18/17 06:00a ║ 6/18/18 05:00p ║ Travel to Install ║
╠═════╬════════╬═════════════════╬════════════════╬═══════════════════╣
║ 3 ║ Rigger ║ 6/19/17 08:00a ║ 6/19/17 06:00p ║ Install ║
╠═════╬════════╬═════════════════╬════════════════╬═══════════════════╣
║ 1 ║ Rigger ║ 6/20/17 07:00a ║ 6/20/17 04:00p ║ Travel Home ║
╠═════╬════════╬═════════════════╬════════════════╬═══════════════════╣
║ 2 ║ Rigger ║ 6/20/17 08:00a ║ 6/20/17 06:00p ║ Install ║
╠═════╬════════╬═════════════════╬════════════════╬═══════════════════╣
║ 2 ║ Rigger ║ 6/21/17 07:00a ║ 6/21/17 04:00p ║ Travel Home ║
╚═════╩════════╩═════════════════╩════════════════╩═══════════════════╝
...将输出......
╔═══════════╦═════════╦═════════╦════════════════════════════════════════════╗
║ ROLE ║ START ║ END ║ DESCRIPTION ║
╠═══════════╬═════════╬═════════╬════════════════════════════════════════════╣
║ Rigger #1 ║ 6/15/17 ║ 6/21/17 ║ Trav | Prep | Trav | Install | Trav | Trav ║
╠═══════════╬═════════╬═════════╬════════════════════════════════════════════╣
║ Rigger #2 ║ 6/18/17 ║ 6/21/17 ║ Trav | Install | Trav ║
╠═══════════╬═════════╬═════════╬════════════════════════════════════════════╣
║ Rigger #3 ║ 6/18/17 ║ 6/20/17 ║ Trav | Install ║
╚═══════════╩═════════╩═════════╩════════════════════════════════════════════╝
在正常文档使用期间,这整个操作会多次发生,如果数据顺序发生变化(这是可能的),它也会在操作之间产生不一致的结果。
我不希望将源数组排序为操作的一部分,因为它是一个昂贵的过程,一旦表达到10行就会增加明显的延迟,即使使用merge-sort或quick-sort也是如此。 / p>
我试图尽可能优化这个过程;许多其他输出使用这个扩展阵列,其中一些有效地提供实时反馈,因此每次用户输入数据时操作都会运行。
用户可以选择的可能描述列表是预先确定的
╔═══════════════════════╗
║ Travel to Prep ║
╠═══════════════════════╣
║ Travel & Prep ║
╠═══════════════════════╣
║ Prep ║
╠═══════════════════════╣
║ Prep & Travel ║
╠═══════════════════════╣
║ Travel to Install ║
╠═══════════════════════╣
║ Travel & Install ║
╠═══════════════════════╣
║ Install ║
╠═══════════════════════╣
║ Travel to Show ║
╠═══════════════════════╣
║ Rehearsal ║
╠═══════════════════════╣
║ Show ║
╠═══════════════════════╣
║ Show & Dismantle ║
╠═══════════════════════╣
║ Travel to Dismantle ║
╠═══════════════════════╣
║ Dismantle ║
╠═══════════════════════╣
║ Travel Home ║
╠═══════════════════════╣
║ Travel to Site Survey ║
╠═══════════════════════╣
║ Site Survey ║
╠═══════════════════════╣
║ Dark Day ║
╚═══════════════════════╝
我认为这实际上是一个有向图,边缘都有一个方向(大多数是单向),一些节点可以自循环。我为上面的列表构建了一个邻接矩阵,因为这似乎是确定赋值顺序是否有效的逻辑方法。
是否有一种有效的方法可以确保特定角色的所有路径都是有效的遍历路径,以及如果一个或多个路径无效,如何最好地重新分配角色实例号?
或者是否可以在扩展操作期间在路径遍历的每个级别使用描述值的子集,以确保正确分配角色实例编号以开始?
我应该关注图论的特定领域吗?图表是正确的方法吗?是否存在可行/更有效的替代方法?
非常感谢任何建议/帮助。
由于
答案 0 :(得分:1)
关注以下引用:
我不希望将源数组排序为 操作,因为它是一个昂贵的过程,一次增加明显的滞后 即使使用merge-sort或,表也会进入10行 快速排序。
我注意到你将你的来源称为数组。那么用户是否将信息输入到工作表范围中并从那里使用VBA将数据加载到数组中?如果是这样,我想知道你是否了解VBA中的Recordsets。从我的回忆中,他们并不是很简单地读取数据,但是一旦数据进入,你就可以在其上运行SQL查询。这并不能解决性能问题,但我认为你做的比在10次记录之后获得更好。而且您可能不必担心排序方法。如果您不熟悉SQL,我会说,鉴于您正在尝试的事情,它绝对值得花时间。
Here's一个做过它的人。他有不同的理由这样做,但你可以在你的情况下应用它。
顺便说一下,如果您的用户对Excel很满意,那么在工作时,他们可能仍然熟悉MS Access。无需安装新软件,您可以在不将数据加载到新对象的情况下执行SQL,并且可以更轻松地处理表单和开发报表。
答案 1 :(得分:0)
嗯,部署在Office产品中的软件,主要是Excel,有时是用户的梦想。这并不意味着您应该将代码写入特定的电子表格文件(.xlsm)。
您还有其他选项可以改善隔离,并且可以轻松地转换为其他解决方案。一些可能性:
1)VBA中的ExcelAddIn:https://msdn.microsoft.com/en-us/library/office/gg597509%28v=office.14%29.aspx
2).NET中的ExcelAddIn:https://msdn.microsoft.com/en-us/library/cc668205.aspx
甚至,
3)XLL,如果表现有问题(似乎不是你的情况)https://msdn.microsoft.com/en-us/library/office/bb687829.aspx
我希望有所帮助!