【问题标题】:More efficient way to combine two worksheets data合并两个工作表数据的更有效方法
【发布时间】:2015-08-25 19:53:21
【问题描述】:

我有一个合并两张数据表的工作方法;但是,它比我希望的要慢一些。我想知道是否有人知道合并数据的更快方法。

我比较了两张分别有大约 700 行和 400 行的工作表。表 1 中的数据包含唯一的飞机航班号以及该航班的每个航段的单独行(一个任务编号可能有 5 或 6 个航班的“航段”,每个航段在自己的行中)。表 2 包含相同的任务编号,但告诉我有多少乘客和多少货物(称为“升降机”),如果有的话,在某些腿上。此表中仅列出了那些带有“升降机”的腿。一些升降机在船上停留多条腿。未显示空腿。

我需要将两者结合起来,以便将表 2 中的乘客和货物信息添加到表 1 上任务的正确航段。这为我提供了该任务的完整详细视图。我将这些数据显示在我在 Excel 中创建的图形地图上。

这是我目前使用的代码:

Sub combineDataTest()

Application.ScreenUpdating = False

Dim i As Long, j As Long
Dim lastRow As Long, lastRow2 As Long

Dim ws2 As Worksheet, ws3 As Worksheet
Set ws2 = ThisWorkbook.Sheets("Full Missions")
Set ws3 = ThisWorkbook.Sheets("Passengers and Cargo")

ws2.Columns("H:J").Cells.Clear

lastRow = findLastRow("Passengers and Cargo") 'calls a function that returns the last row
lastRow2 = findLastRow("Full Missions") 'calls a function that returns the last row

' Add column names on mission sheet
ws2.Range("H1").Value = "LIFT CODE"
ws2.Range("I1").Value = "LIFT PASSENGERS"
ws2.Range("J1").Value = "LIFT CARGO"

For i = 2 To lastRow
    For j = 2 To lastRow2

        ' If the mission numbers match
        If ws3.Range("A" & i).Value = Left(ws2.Range("D" & j).Value, 9) And _
        ws2.Range("E" & j).Value >= ws3.Range("C" & i).Value And _
        ws2.Range("E" & j).Value <= ws3.Range("D" & i).Value - 1 Then

            If ws2.Range("H" & j).Value = "" Then
                ws2.Range("H" & j).Value = ws3.Range("Q" & i).Value
                ws2.Range("I" & j).Value = ws3.Range("O" & i).Value
                ws2.Range("J" & j).Value = ws3.Range("P" & i).Value
            Else
                ws2.Range("H" & j).Value = ws2.Range("H" & j).Value & ", " & ws3.Range("Q" & i).Value
                ws2.Range("I" & j).Value = ws2.Range("I" & j).Value + ws3.Range("O" & i).Value
                ws2.Range("J" & j).Value = ws2.Range("J" & j).Value + ws3.Range("P" & i).Value
            End If

        End If

    Next j
Next i

如果您对如何运行代码有更好的了解,我将不胜感激。我不确定通过数组运行它是否会更快,或者这是否和它一样好。

编辑:以下是一些示例数据表。这不是真实数据。

完整任务:

ICAO | LONG   | LAT   | MISSION_ACFT  |LEG| ARRIVAL          | DEPART
-------------------------------------------------------------------------------
KRIC | -77.32 | 37.5  | ABC155894_C26 | 1 | 20-JUN-2015 1101 | 20-JUN-2015 1101
KGTR | -88.58 | 33.43 | ABC155894_C26 | 2 | 20-JUN-2015 1433 | 20-JUN-2015 1348
KNGU | -76.28 | 36.93 | ABC155894_C26 | 3 | 20-JUN-2015 1800 | 20-JUN-2015 1715
KCLT | -80.93 | 35.2  | ABC155894_C26 | 4 | 20-JUN-2015 1940 | 20-JUN-2015 1910
KGSO | -79.93 | 36.1  | ABC155894_C26 | 5 | 20-JUN-2015 2035 | 20-JUN-2015 2005
KRDU | -78.78 | 35.87 | ABC155894_C26 | 6 | 20-JUN-2015 2130 | 20-JUN-2015 2100
KNGU | -76.28 | 36.93 | ABC155894_C26 | 7 | 20-JUN-2015 2235 | 20-JUN-2015 2205
KRIC | -77.32 | 37.5  | ABC155894_C26 | 8 | 20-JUN-2015 2300 | 20-JUN-2015 2300
KRIC | -77.32 | 37.5  | ABC156469_C26 | 1 | 26-JUN-2015 1101 | 26-JUN-2015 1101
KVQQ | -81.87 | 30.22 | ABC156469_C26 | 2 | 26-JUN-2015 1408 | 26-JUN-2015 1323
KHST | -80.38 | 25.48 | ABC156469_C26 | 3 | 26-JUN-2015 1616 | 26-JUN-2015 1531
KMCF | -82.52 | 27.83 | ABC156469_C26 | 4 | 26-JUN-2015 1748 | 26-JUN-2015 1703
KVQQ | -81.87 | 30.22 | ABC156469_C26 | 5 | 26-JUN-2015 1910 | 26-JUN-2015 1825
KRIC | -77.32 | 37.5  | ABC156469_C26 | 6 | 26-JUN-2015 2121 | 26-JUN-2015 2121
KRIC | -77.32 | 37.5  | ABC156733_C26 | 1 | 27-JUN-2015 1533 | 27-JUN-2015 1533
KDAA | -77.17 | 38.7  | ABC156733_C26 | 2 | 27-JUN-2015 1643 | 27-JUN-2015 1558
KCHS | -80.03 | 32.88 | ABC156733_C26 | 3 | 27-JUN-2015 1916 | 27-JUN-2015 1831
KRIC | -77.32 | 37.5  | ABC156733_C26 | 4 | 27-JUN-2015 2038 | 27-JUN-2015 2038
KRIC | -77.32 | 37.5  | ABC156773_C26 | 1 | 28-JUN-2015 1113 | 28-JUN-2015 1113
KNCA | -77.43 | 34.7  | ABC156773_C26 | 2 | 28-JUN-2015 1246 | 28-JUN-2015 1201
KLSF | -84.98 | 32.32 | ABC156773_C26 | 3 | 28-JUN-2015 1526 | 28-JUN-2015 1441

乘客和货物:(为节省空间而删除了多余的数据)

MISSION   | B | ONL|OFFL| E | F | G | H | I | J | K | L | M | N |PAX|CAR|LIFT ID
--------------------------------------------------------------------------------
ABC155894 |   |  1 |  2 |   |   |   |   |   |   |   |   |   |   | 2 |100| E
ABC155894 |   |  3 |  4 |   |   |   |   |   |   |   |   |   |   | 2 |155| A
ABC155894 |   |  4 |  5 |   |   |   |   |   |   |   |   |   |   | 2 |155| B
ABC155894 |   |  5 |  6 |   |   |   |   |   |   |   |   |   |   | 2 |155| C
ABC155894 |   |  6 |  7 |   |   |   |   |   |   |   |   |   |   | 2 |155| D
ABC156469 |   |  2 |  3 |   |   |   |   |   |   |   |   |   |   | 2 |220| A
ABC156469 |   |  3 |  4 |   |   |   |   |   |   |   |   |   |   | 2 |220| B
ABC156469 |   |  4 |  5 |   |   |   |   |   |   |   |   |   |   | 2 |220| C
ABC156733 |   |  2 |  3 |   |   |   |   |   |   |   |   |   |   | 2 |0  | A
ABC156773 |   |  2 |  3 |   |   |   |   |   |   |   |   |   |   | 2 |0  | A

【问题讨论】:

  • 那么,工作表 2 上的所有数据都将在工作表 1 上吗?工作表 2 中的每个航班号也会匹配工作表 1 上的一个单元格/行或多个单元格/行吗?
  • SO 通常用于解决代码问题或错误,我认为更适合在Code Review 提出您的问题,这是审查代码和提供改进提示的 SE 地方 :)
  • 您有嵌套循环,因此您要进行 280,000 次比较。您可以按任务编号对工作表进行排序吗?然后,您将能够按顺序处理这两个工作表。
  • Tim - 航班号和所有航段号都在完整任务表上。乘客表上列出了电梯,以及它们所在的航班号和航段。
  • 龙——我明白了。我不知道代码审查。我也会给他们一个机会。

标签: vba excel loops excel-2010


【解决方案1】:

通常要快得多

  • 将数据读入 VBA 数组(一步即可完成)
  • 遍历数组并收集所需数据
  • 按所需顺序创建所需结果的数组
  • 将此数组写入工作表(也可以一步完成)

根据数据的复杂性,创建具有所需属性的用户定义对象(类)可能会有所帮助,然后将这些对象收集到一个集合中作为结果数组的源。

有关用户定义对象的更多信息,请参阅Chip Pearson's "Introduction to Classes"

可以在Combine Rows with duplicate values, merge cells if different我的回答中找到使用这种方法的示例,尽管只有一个数据表。

这种方法通常至少比来回工作表快一个数量级。

这里有一些代码示例可以帮助您入门。检查速度。

重命名类模块cLegCargoAndPassengers 将工作表添加到您的工作簿并将其命名为 Combined

类模块

Option Explicit
Private pMission As String
Private pLeg As Long
Private pMissionData As Variant
Private pPassengers As Long
Private pCargo As Long
Private pLiftCode As String
Private pLiftCodes As Collection

Private Sub Class_Initialize()
    Set pLiftCodes = New Collection
End Sub

Public Property Get Mission() As String
    Mission = pMission
End Property
Public Property Let Mission(Value As String)
    pMission = Value
End Property

Public Property Get Leg() As Long
    Leg = pLeg
End Property
Public Property Let Leg(Value As Long)
    pLeg = Value
End Property

Public Property Get MissionData() As Variant
    MissionData = pMissionData
End Property
Public Property Let MissionData(Value As Variant)
    pMissionData = Value
End Property

Public Property Get Passengers() As Long
    Passengers = pPassengers
End Property
Public Property Let Passengers(Value As Long)
    pPassengers = Value
End Property

Public Property Get Cargo() As Long
    Cargo = pCargo
End Property
Public Property Let Cargo(Value As Long)
    pCargo = Value
End Property

Public Property Get LiftCode() As String
    LiftCode = pLiftCode
End Property
Public Property Let LiftCode(Value As String)
    pLiftCode = Value
End Property



Public Property Get LiftCodes() As Collection
    Set LiftCodes = pLiftCodes
End Property

Function Add(Value As String)
    LiftCodes.Add Value
End Function

常规模块

Option Explicit
Sub CombineData()
    Dim cLCP As cLegCargoAndPassengers, colLCP As Collection
    Dim I As Long, J As Long, K As Long, L As Long, S As String, V() As Variant
    Dim wsFM As Worksheet, wsPAC As Worksheet, wsCOMB As Worksheet
    Dim vFM As Variant, vPAC As Variant, vCOMB() As Variant
    Dim lFirstKey As Long, lLastKey As Long, sKeys() As String

Set wsFM = Worksheets("Full Missions")
Set wsPAC = Worksheets("Passengers and Cargo")
Set wsCOMB = Worksheets("Combined")

'read data into arrays
'could calculate the last column, and/or some of the leg columns,but I hard coded them for now

With wsFM
    vFM = .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)).Resize(columnsize:=7)
End With
With wsPAC
    vPAC = .Range("A1", .Cells(.Rows.Count, "A").End(xlUp)).Resize(columnsize:=17)
End With

'Collect and combine the data
'First get the full missions and tease out the important data

Set colLCP = New Collection
For I = 2 To UBound(vFM, 1)
    Set cLCP = New cLegCargoAndPassengers

    'Get the whole row
    'Could get each component separately, if needed
    ReDim V(1 To UBound(vFM, 2))
        For J = 1 To UBound(V)
            V(J) = vFM(I, J)
        Next J
    With cLCP
        .MissionData = V
        .Mission = Trim(Left(vFM(I, 4), InStr(1, vFM(I, 4), "_") - 1))
        .Leg = vFM(I, 5)
        colLCP.Add Item:=cLCP, Key:=.Mission & "|" & .Leg
    End With
Next I

'Now combine the Passenger and cargo data
For I = 2 To UBound(vPAC, 1)
    'Generate all possible keys
    'allows for possibility of passengers being on for more than two legs

    lFirstKey = vPAC(I, 3)
    lLastKey = vPAC(I, 4)
    ReDim sKeys(1 To lLastKey - lFirstKey)
    K = 0
    For J = lFirstKey To lLastKey - 1
        K = K + 1

        'Trim may be superfluous, but trailing space present in your sample data
        sKeys(K) = Trim(vPAC(I, 1)) & "|" & J
    Next J

    'Add the data for each leg
    For K = 1 To UBound(sKeys)
    With colLCP(sKeys(K))
        .LiftCode = vPAC(I, 17)
        .Add (.LiftCode)
        .Passengers = .Passengers + vPAC(I, 15)
        .Cargo = .Cargo + vPAC(I, 16)
    End With
    Next K
Next I

'Now Combine the data
'Row 0 for the headers
K = UBound(vFM, 2)
ReDim vCOMB(0 To colLCP.Count, 1 To K + 3)

'Populate headers
For I = 1 To K
    vCOMB(0, I) = vFM(1, I)
Next I
vCOMB(0, K + 1) = "LIFT CODE"
vCOMB(0, K + 2) = "LIFT PASSENGERS"
vCOMB(0, K + 3) = "LIFT CARGO"

'Populate data
For I = 1 To colLCP.Count
    With colLCP(I)
        V = .MissionData
        For J = 1 To UBound(V)
            vCOMB(I, J) = V(J)
        Next J

        S = ""
        For L = 1 To .LiftCodes.Count
            S = S & "," & .LiftCodes(L)
        Next L
        S = Mid(S, 2)

        vCOMB(I, K + 1) = S
        vCOMB(I, K + 2) = .Passengers
        vCOMB(I, K + 3) = .Cargo
    End With
Next I

'Write the results
With wsCOMB.Range("A1").Resize(UBound(vCOMB, 1) + 1, UBound(vCOMB, 2))
    .EntireColumn.Clear
    .Value = vCOMB
    With .Rows(1)
        .Font.Bold = True
        .HorizontalAlignment = xlCenter
    End With
    .EntireColumn.AutoFit
End With
End Sub

【讨论】:

  • 这当然是一个很好的答案,但我确实认为您确实需要至少展示四个步骤中的每一个的示例。那么这将是一个很好的答案。
  • @Enigmativity 我认为 OP 最好自己完成大部分工作,并参考 Pearson 关于课程的文章,但我会添加一些示例。
  • Stack Overflow 不是关于 OP,而是关于构建一个高质量的问题和答案库。如果它对 OP 有帮助,那将是一个奖励,但这不是目的。你不应该让所有未来的读者自己做这项工作。
  • @Enigmativity 在这种情况下,我将发布另一个问题的链接,该问题提供了使用 UDO 集合组合数据的示例。
  • 无论哪种情况,我都非常感谢您的回答。我会查看这两个链接,看看它是否能让我到达我需要去的地方。我应该可以在星期一回去工作时看看。 // Enigma - 我也感谢您在扩展答案方面的帮助。我对数组或创建类的工作不多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-04
  • 2013-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-07
  • 2021-06-11
相关资源
最近更新 更多