【问题标题】:Advice on what methodology/data structure/algorithm to use关于使用什么方法/数据结构/算法的建议
【发布时间】: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


【解决方案1】:

嗯,部署集成在 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

希望对你有帮助!

【讨论】:

    【解决方案2】:

    关注以下引用:

    我不希望将源数组作为 操作,因为这是一个昂贵的过程,会增加一次明显的延迟 即使使用合并排序或 快速排序。

    我注意到您将源称为数组。那么用户是否将信息输入工作表范围,然后使用 VBA 将数据加载到数组中?如果是这样,我想知道您是否知道 VBA 中的记录集。根据我的回忆,它们并不是很容易读取数据,但是一旦数据进入,您就可以对其运行 SQL 查询。这不能避免性能问题,但我认为你会比在 10 条记录后受到打击要好。而且您可能不必担心排序方法。如果您不熟悉 SQL,我会说考虑到您正在尝试做的事情,这绝对值得花时间。

    Here's 一个这样做的人。他这样做有不同的理由,但你可以在你的情况下应用它。

    顺便说一句,如果您的用户对 Excel 感到满意,那么在工作中,他们可能仍然对 MS Access 感到满意。无需安装新软件,无需将数据加载到新对象即可执行 SQL,并且可以更轻松地处理表单和开发报告。

    【讨论】:

      猜你喜欢
      • 2012-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-19
      • 2017-09-01
      相关资源
      最近更新 更多