VBA数组按字段名作为参数排序

时间:2015-05-14 17:48:13

标签: arrays excel vba excel-vba

这里的交易......在试图超越我对Excel VBA中的类模块的恐惧时,我决定创建一个类是一个数组,然后添加函数(方法)来添加元素,排序一个这些是我在正常模块中作为函数/ ​​subs重写的东西,但希望使用类可能是向前迈出的一步。

代码模块

Public Type Thing
   Name As String
   SomeNumber As Double
End Type

课程模块

Private pSomething() As Thing

接下来是所有常用的公共LET和GET,以及用于向数组中插入新值的函数。然后我进入排序功能/方法。按Name或SomeNumber排序没有问题,但到目前为止需要两个函数/方法。我想参数化为单个函数/ mehod然后使用可选参数来控制要使用的字段。以下作品,但似乎有点笨重

Function SortByField(Optional FieldName As String, Optional SortOrder As vbaSortOrder)
    Dim strTemp As Thing
    If SortOrder = 0 Then SortOrder = soBottomToTop
    If Len(FieldName) = 0 Then FieldName = "Name"
    Dim i As Long
    Dim j As Long
    Dim lngMin As Long
    Dim lngMax As Long
    lngMin = LBound(pSomething)
    lngMax = UBound(pSomething)
    For i = lngMin To lngMax - 1
      For j = i + 1 To lngMax
        If IIf(SortOrder = soBottomToTop, _
                              IIf(FieldName = "Name", pSomething(i).Name > pSomething(j).Name, _
                                                       pSomething(i).SomeNumber > pSomething(j).SomeNumber), _
                              IIf(FieldName = "Name", pSomething(i).Name < pSomething(j).Name, _
                                                       pSomething(i).SomeNumber < pSomething(j).SomeNumber)) _
                              Then
          strTemp = pSomething(i)
          pSomething(i) = pSomething(j)
          pSomething(j) = strTemp
        End If
      Next j
    Next i
End Function

我想做的是取代以下(在这个gawdawful IF(IIF ...)无意义的第二部分中它的同伴

IIf(FieldName = "Name", pSomething(i).Name > pSomething(j).Name, pSomething(i).SomeNumber > pSomething(j).SomeNumber)

......用这样的东西

"pSomething(i)." & FieldName > "pSomething(j)." & FieldName

直接问题:如何获取要评估/转换为代码的字符串?

间接问题:是否有其他技术可以传入字段名并将其视为字符串以外的其他内容?

提前感谢任何帮助,帮助,指导,指导,参考,建议,这是一个愚蠢的错误或嘲弄的评论:)。

3 个答案:

答案 0 :(得分:3)

BiggerDon, 我试图遵循你的代码,你是对的,嵌套的IIF是gawdawful。我可以建议您使用SELECT CASE语句重写代码。这可能会有所帮助。 此外,您想要实现的目标是什么?对于单维数组而言,这几乎看起来有点过分。

您可以使用内置的其他Excel VBA方法。

我刚刚对网格排序进行了快速的互联网搜索,并且遇到了Pearson的网站http://www.cpearson.com/excel/SortingArrays.aspx

你可以查看一下。

答案 1 :(得分:1)

@BiggerDon, 如何为每个字段添加属性的自定义类型类。 遍历记录并将它们添加到自定义类的集合中。执行此操作时,您可以确定将哪个字段用作集合的键。 然后使用这里介绍的东西。 How do I sort a collection?

答案 2 :(得分:0)

考虑一种基于自定义类而不是类型的方法,并使用VBScript中的Eval()方法来评估项的字段值。

将以下代码放在 VBA模块

Sub TestStorage()
    Dim Room As New Storage
    Dim i As Long
    Dim Elem As Object
    Dim Item As Variant
    Dim Result As String

    For i = 1 To 10
        Set Elem = New OrdinalType
        Elem.Name = GetRandomFruit
        Elem.Index = i
        Room.Push Elem
    Next
    For i = 11 To 20
        Set Elem = New ExtendedType
        Elem.Name = GetRandomFruit
        Elem.Index = i
        Elem.Additional = "Extended"
        Room.Push Elem
    Next
    Set Elem = Nothing

    ShowList Room.GetContent

    Room.SortByField "Name", True
    ShowList Room.GetContent

    Room.SortByField "Index", False
    ShowList Room.GetContent

End Sub

Sub ShowList(Arr)
    Result = ""
    For Each Item In Arr
        Result = Result & Item.Name & " (" & Item.Index & ")"
        If TypeName(Item) = "ExtendedType" Then
            Result = Result & " " & Item.Additional
        End If
        Result = Result & vbCrLf
    Next
    MsgBox Result
End Sub

Function GetRandomFruit()
    Dim Fruits
    Randomize
    Fruits = Array("Apple", "Apricot", "Banana", "Bilberry", "Blackberry", "Blackcurrant", "Blueberry", "Coconut", "Currant", "Cherry", "Cherimoya", "Clementine", "Date", "Damson", "Durian", "Elderberry", "Fig", "Feijoa", "Gooseberry", "Grape", "Grapefruit", "Huckleberry", "Jackfruit", "Jambul", "Jujube", "Kiwifruit", "Kumquat", "Lemon", "Lime", "Loquat", "Lychee", "Mango", "Mangostine", "Melon", "Cantaloupe", "Honeydew", "Watermelon", "Rock melon", "Nectarine", "Orange", "Passionfruit", "Peach", "Pear", "Plum", "Prune", "Pineapple", "Pomegranate", "Pomelo", "Raisin", "Raspberry", "Rambutan", "Redcurrant", "Satsuma", "Strawberry", "Tangerine", "Ugli Fruit")
    GetRandomFruit = Fruits(LBound(Fruits) + Round(Rnd * (UBound(Fruits) - LBound(Fruits))))
End Function

添加对 Microsoft脚本控件 ActiveX(菜单 - 工具 - 参考)的引用。
将以下代码放在 VBA类模块中,名称{{1} }:

Storage

将以下代码放在 VBA类模块中,名称为Private Content As Variant Private SC As MSScriptControl.ScriptControl Private Sub Class_Initialize() Set SC = New MSScriptControl.ScriptControl SC.Language = "VBScript" SC.ExecuteStatement "Function EvalProp(Item, Name): EvalProp = Eval(""Item."" & Name): End Function" Content = Array() End Sub Private Function GetValue(ObjectInstance, PropertyName) GetValue = SC.Run("EvalProp", ObjectInstance, PropertyName) End Function Public Sub Push(Item) ReDim Preserve Content(UBound(Content) + 1) Set Content(UBound(Content)) = Item End Sub Public Function Pop() Set Pop = Content(UBound(Content)) ReDim Preserve Content(UBound(Content) - 1) End Function Public Sub SortByField(Optional PropName As String = "Name", Optional SortAsc As Boolean = True) Dim i As Long Dim j As Long Dim l As Long Dim u As Long Dim a As Variant Dim b As Variant Dim tmp As Object l = LBound(Content) u = UBound(Content) For i = l To u - 1 For j = i + 1 To u a = GetValue(Content(i), PropName) b = GetValue(Content(j), PropName) If (a > b And SortAsc) Or (a < b And Not SortAsc) Then Set tmp = Content(j) Set Content(j) = Content(i) Set Content(i) = tmp End If Next j Next i End Sub Public Function GetContent() GetContent = Content End Function Public Function GetSize() GetSize = UBound(Content) - LBound(Content) + 1 End Function

OrdinalType

将以下代码放在 VBA类模块中,名称为Public Name As String Public Index As Double

ExtendedType

此示例显示如何在存储对象中创建和存储不同类型的实例,这些实例能够处理这些类型(在此特定情况下) - 将字符串作为排序字段名称进行排序。请注意,此类VBS注射异常,通常不是最佳做法。关于处理速度 - 我的N7110上Public Name As String Public Index As Double Public Additional As String 通话大约需要15 mksecs。