【发布时间】:2017-11-20 08:31:32
【问题描述】:
我正在为我正在尝试解决的问题寻找有关方法/数据结构/算法方法的一些建议。
我正在用 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 行,即使使用合并排序或快速排序,也会增加明显的延迟。
我正在尝试尽可能优化此过程;许多其他输出使用这个扩展数组,其中一些有效地提供实时反馈,因此每次用户输入数据时操作都会运行。
用户可以选择的可能描述列表是预先确定的
╔═══════════════════════╗
║ 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 ║
╚═══════════════════════╝
我认为这实际上是一个有向图,所有的边都有一个方向(大多数是单向的)并且一些节点可以自循环。我已经为上面的列表构建了一个邻接矩阵,因为这似乎是确定分配顺序是否有效的合乎逻辑的方式。
是否有一种有效的方法来确保特定角色的所有路径都是有效的遍历路径,以及如果一个或多个路径无效,如何最好地重新分配角色实例编号?
或者是否可以在扩展操作期间在路径遍历的每个级别使用描述值的子集来确保正确分配角色实例编号?
我应该关注图论的某个特定领域吗?图表是正确的方法吗?是否有替代方法可以工作/更有效?
我们将不胜感激地收到任何建议/帮助。
谢谢
【问题讨论】:
-
我把描述看了 3 遍,但你真正想解决什么问题?从您的数据中,您预期的数据是什么?很多时候,如果你能向陌生人解释你的问题,你就会得到解决方案。这看起来就像你被困在一个如何而忘记了什么。你能举一些输入、输出好、输出错误的例子吗?
标签: algorithm data-structures language-agnostic graph-theory