如何遍历不均匀的数据块

时间:2019-06-10 18:10:41

标签: excel vba

所以基本上我正在处理一张数据表,最多约200,000行。数据的格式如下所示(伪数据)。我正在尝试分析每个周期,以确保每个周期都达到了一定的温度和压力范围(例如,对于任何给定的周期,温度都在120-130之间)。

cycle    temperature    pressure 
  1           120          321
  1           121          332
  1           122          323
  2           123          334
  2           124          326
  3           125          337
  3           126          328
  3           127          339
  3           128          320
  4           129          334    

我很自信能够使用一些if语句来查看是否已达到每个温度/压力,但是给我带来麻烦的那部分是能够将其分解为能够逐周期分析(例如,周期1在范围内,周期2在范围内)。如果周期长度相同,这将是相当简单的,但是它们通常通常会变化1或2个值。

我目前的想法是查看第一个循环值,然后遍历各行。如果每行的周期值等于所需值(从周期1开始),那么将评估我想要的if语句。如果到达周期2,则我们增加var,使其等于周期2。

var = ThisWorkbook.Sheets("Data").Range("A2")
For i = 2 To lastRow

    If ThisWorkbook.Sheets("Data").Cells(i, 1) = var Then
        'various if statements go here
    Else
        var = var + 1
    End If
next i

现在这有很多问题,一个是每个新循环的第一个值被跳过。但是主要问题是完全忽略了“逐周期”评估的能力。

大多数人只是想获得一些帮助,以考虑如何将其按周期分为几部分。我的直觉告诉我嵌套的循环,但是我不确定如何说“这是一个新的循环,请转到下一个循环”。

3 个答案:

答案 0 :(得分:1)

您应该能够执行以下操作(假设ColA按cycle排序并且没有空单元格)

Dim c as range, i as long

Set c = ThisWorkbook.Sheets("Data").Range("A2")

Do While c.Value <> ""
    i = application.Countif(c.parent.columns(1),c.value)

    'Process i rows of data


    Set c = c.offset(i, 0) '<< start of next block
Loop

答案 1 :(得分:0)

这是您可以根据需要调整的功能。它以数据范围为输入,查找值超出范围的所有周期,并返回不良周期“标题编号”的集合。可以将它们放在另一个范围内,在消息框中打印,或以其他方式处理。

Public Function findBadCycles(rngRangeToCheck As Range) As Collection

    Dim dblMinTemp As Double
    Dim dblMaxTemp As Double
    Dim dblMinPress As Double
    Dim dblMaxPress As Double

    dblMinTemp = 120
    dblMaxTemp = 130
    dblMinPress = 320
    dblMaxPress = 340

    Dim colBadCycles As Collection
    Set colBadCycles = New Collection

    Dim i As Long
    For i = 2 To rngRangeToCheck.Rows

        If rngRangeToCheck.Cells(i, 2) < dblMinTemp Or rngRangeToCheck.Cells(i, 2) > dblMaxTemp Then
            colBadCycles.Add rngRangeToCheck.Cells(i, 1).Value
        elseif (rngRangeToCheck.Cells(i, 3) < dblMinPress) Or (rngRangeToCheck.Cells(i, 3) > dblMaxPress):
            colBadCycles.Add rngRangeToCheck.Cells(i, 1).Value
        End If

    Next i

    Set findBadCycles = colBadCycles

End Function

答案 2 :(得分:0)

对于200,000行,使用Variant Array方法会更快

一个简单的for循环遍历数组,标识每个循环的第一行和最后一行,然后执行该循环的循环以处理数据。

像这样的东西

我提供了一个示例,说明如何处理数据:返回“温度和压力”的“最小”,“最大”,“平均”和“人口标准偏差”,该偏差位于每个“循环”的第一项旁边的行中 (由于您没有说出实际的处理方式,因此请将其作为模板并进行更新以满足您的需求)

在我的硬件上,随机数据集200,000行上的运行时间为1.7秒

Sub Demo()
    Dim rngDat As Range
    Dim rngRes As Range
    Dim dat As Variant
    Dim res As Variant
    Dim FirstOfCycle As Long
    Dim LastOfCycle As Long
    Dim Cycle As Long
    Dim i As Long, j As Long

    Set rngDat = Range(Cells(2, 3), Cells(Rows.Count, 1).End(xlUp))
    'Example: set return range to 4 columns next to data
    Set rngRes = rngDat.Columns(rngDat.Columns.Count + 1).Resize(, 8)
    dat = rngDat.Value2
    rngRes.ClearContents
    res = rngRes.Value2

    FirstOfCycle = 1
    For i = 1 To UBound(dat, 1) - 1
        If dat(i + 1, 1) <> dat(i, 1) Then
            LastOfCycle = i
            Cycle = dat(i, 1)
            ProcessCycle dat, res, FirstOfCycle, LastOfCycle
            FirstOfCycle = i + 1
        End If
    Next
    If dat(i, 1) = dat(FirstOfCycle, 1) Then
        ProcessCycle dat, res, FirstOfCycle, i
    Else
        ProcessCycle dat, res, i, i
    End If


    rngRes.Value = res

End Sub

Private Sub ProcessCycle(dat As Variant, result As Variant, FirstOfCycle As Long, LastOfCycle As Long)
    Dim i As Long
    Dim MnT As Double, MxT As Double
    Dim AvgT As Double, SdT As Double
    Dim SumT As Double, SumT2 As Double
    Dim MnP As Double, MxP As Double
    Dim AvgP As Double, SdP As Double
    Dim SumP As Double, SumP2 As Double

    MnT = dat(FirstOfCycle, 2)
    MxT = dat(FirstOfCycle, 2)
    MnP = dat(FirstOfCycle, 3)
    MxP = dat(FirstOfCycle, 3)
    For i = FirstOfCycle To LastOfCycle
        If dat(i, 2) < MnT Then MnT = dat(i, 2)
        If dat(i, 2) > MxT Then MxT = dat(i, 2)
        If dat(i, 3) < MnP Then MnP = dat(i, 3)
        If dat(i, 3) > MxP Then MxP = dat(i, 3)
        SumT = SumT + dat(i, 2)
        SumT2 = SumT2 + dat(i, 2) ^ 2
        SumP = SumP + dat(i, 3)
        SumP2 = SumP2 + dat(i, 3) ^ 2
    Next
    result(FirstOfCycle, 1) = MnT
    result(FirstOfCycle, 2) = MxT
    result(FirstOfCycle, 3) = SumT / (LastOfCycle - FirstOfCycle + 1)
    result(FirstOfCycle, 4) = Sqr(SumT2 / (LastOfCycle - FirstOfCycle + 1) - result(FirstOfCycle, 3) ^ 2)

    result(FirstOfCycle, 5) = MnP
    result(FirstOfCycle, 6) = MxP
    result(FirstOfCycle, 7) = SumP / (LastOfCycle - FirstOfCycle + 1)
    result(FirstOfCycle, 8) = Sqr(SumP2 / (LastOfCycle - FirstOfCycle + 1) - result(FirstOfCycle, 7) ^ 2)
End Sub