【问题标题】:Excel VBA Find cell address in range based on min to max value of correspoding rangeExcel VBA根据相应范围的最小值到最大值查找范围内的单元格地址
【发布时间】:2016-11-05 11:11:44
【问题描述】:

我正在研究算法基础工具;请帮助我解决以下问题。

1.首先我根据一个标准(动态)找到行号。假设行号为 5,并且它有一组 Value From (B5:F5)

Set FindRow = SearchRange.Find(Sheet1.Cells(xRow, 2).Text, LookIn:=xlValues, lookat:=xlWhole)    
MyRow = FindRow.Row

2.我有带有数值的标题(B1:F1)

3.然后我需要找到列号,即MyCol是(B1:F1)中最小值单元格的列号

4.然后我用If Cells(MyRow,MyCol)="ABC" Then test fail 测试一个条件,我需要再次找到 (B1:F1) 和列号中的下一个最小值,即 MyCol,直到我满足条件。

我尝试了数组,我无法找到解决方案,任何帮助将不胜感激。提前致谢。

【问题讨论】:

  • 请从您的方法中发布代码。

标签: excel multidimensional-array vba


【解决方案1】:

如果我理解正确,您需要的是索引排序。许多语言提供索引排序作为标准功能。 VBA 既没有标准排序也没有索引排序。

使用传统的数组排序,值在数组中进行排序。例如:假设我有一个包含值的数组:

A     D     B     E     C

如果我将该数组传递给排序,则返回为:

A     B     C     D     E

但有时您无法对数组进行排序。在您的情况下,该数组是一系列列标题。您无法对这些标题进行排序,因为它们属于它们的列。您将不得不对列进行排序,这充其量是不切实际的,而且可能是不可接受的,因为列的顺序将意味着什么。

使用索引排序,您可以创建数组键和索引:

Keys    A     D     B     E     C
Indices 1     2     3     4     5

这两个数组都被传递给排序,保持键不变并对索引进行排序以给出:

Indices 1     3     5     2     4

使用常规排序,您可以以Array(1) 访问已排序的条目。 Array(2) 等等。使用索引排序,您可以以Array(Indices(1)) 访问已排序的条目。 Array(Indices(2)) 等等。

通过索引获取排序的条目起初可能有点难以理解,而且直接访问源数组无疑更复杂。

下面我给你一个索引插入排序。插入排序简单易懂,但条目数大时速度较慢。您只有五个条目要排序,因此它的性能是可以接受的。查看“插入排序”的 Wiki 条目,了解其工作原理。

DemoSortColumnHeadings 显示如何使用排序以及如何访问列标题。我使用名称ColHeads 而不是KeysColNums 而不是Indices,因为我相信这将使DemoSortColumnHeadings 更容易理解。排序后的ColNums 包含您需要的序列中的列号。排序后,数组ColHeads就不再需要了。

最后一点。 VBA 是我所知道的唯一一种允许您指定数组的下限和上限的语言。大多数语言要求下限为零。我利用这一点将数组的维度定义为(2 到 6)而不是(0 到 4)。这就是为什么数组ColNums 中的值是列号的原因。对于大多数语言,我需要 ColNums(N)+2 来获取列号。

Option Explicit
Sub DemoSortColumnHeadings()

  Const ColFirst As Long = 2  ' Column B = column 2
  Const ColLast As Long = 6   ' Column F = column 6

  Dim ColCrnt As Long
  Dim ColNums() As Long
  Dim InxColNum As Long
  Dim ColHeads() As String

  With Worksheets("Test data")

    ReDim ColHeads(ColFirst To ColLast)
    ReDim ColNums(ColFirst To ColLast)

    For ColCrnt = ColFirst To ColLast
      ColHeads(ColCrnt) = .Cells(1, ColCrnt).Value
      ColNums(ColCrnt) = ColCrnt
    Next


    Debug.Print "Initial sequence"
    Debug.Print "|";
    For ColCrnt = ColFirst To ColLast
      Debug.Print .Cells(1, ColCrnt).Value & "|";
    Next
    Debug.Print

    Call InsertionSort(ColNums, ColHeads)

    Debug.Print "Final sequence"
    Debug.Print "|";
    For InxColNum = LBound(ColNums) To UBound(ColNums)
      ColCrnt = ColNums(InxColNum)
      Debug.Print .Cells(1, ColCrnt).Value & "|";
    Next
    Debug.Print

  End With


End Sub
Public Sub InsertionSort(ByRef Indices() As Long, ByRef Keys() As String)

  Dim Found As Boolean
  Dim I As Long
  Dim InxIFwd As Long
  Dim InxIBack As Long

  For InxIFwd = LBound(Indices) + 1 To UBound(Indices)
    I = Indices(InxIFwd)  ' Save value of current entry in Indices
    ' Find first entry back, if any, such that Keys(I) >= Keys(Indices(InxIBack))
    ' If Keys(I) < Keys(Indices(InxIBack)), set Indices(InxIBack+1) to
    ' Indices(InxIBack). That is move indices for keys greater that Keys(I) down
    ' Indices leaving a space for I nearer the beginning.
    Found = False
    For InxIBack = InxIFwd - 1 To LBound(Indices) Step -1
      If Keys(I) >= Keys(Indices(InxIBack)) Then
        ' Keys(I) belongs after Keys(Indices(InxIBack))
        Indices(InxIBack + 1) = I
        Found = True
        Exit For
      End If
      Indices(InxIBack + 1) = Indices(InxIBack)
    Next
    If Not Found Then
      ' Insertion point for I not found so it belongs at beginning of Indices
      Indices(LBound(Indices)) = I
    End If
  Next

End Sub

【讨论】:

  • @Manish。不客气。注意:我有一个使用相同技术的快速排序实现。在大多数情况下,快速排序是最快的排序,但它难以理解。我的实现可以为 54,000 行工作表创建键和索引,并在 1.5 秒内对索引进行排序。如果需要大数组的排序索引,请记住这一点。
猜你喜欢
  • 1970-01-01
  • 2019-02-11
  • 1970-01-01
  • 2014-11-14
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多