Harlan Grove's Custom Function

Domenic

MrExcel MVP
Joined
Mar 10, 2004
Messages
21,761
Office Version
  1. 365
Platform
  1. Windows
Here's Harlan Grove's custom function, which concatenates values within a range or array...

Code:
Function AConcat(a As Variant, Optional sep As String = "") As String
' Harlan Grove, Mar 2002

    Dim y As Variant

    If TypeOf a Is Range Then
    
        For Each y In a.Cells
            AConcat = AConcat & y.Value & sep
        Next y
    
    ElseIf IsArray(a) Then
    
        For Each y In a
            AConcat = AConcat & y & sep
        Next y
        
    Else
    
        AConcat = AConcat & a & sep
    
    End If
    
    AConcat = Left(AConcat, Len(AConcat) - Len(sep))
    
End Function

As you can see, it first tests for a range and then for an array. Since the IsArray function returns True for both a range and array, is there any reason why the code cannot be re-written as follows?

Code:
Function AConcat(a As Variant, Optional sep As String = "") As String

    Dim y As Variant

    If IsArray(a) Then
    
        For Each y In a
            AConcat = AConcat & y & sep
        Next y
    
    Else
    
        AConcat = AConcat & a & sep
    
    End If
    
    AConcat = Left(AConcat, Len(AConcat) - Len(sep))
    
End Function
 

Excel Facts

Show numbers in thousands?
Use a custom number format of #,##0,K. Each comma after the final 0 will divide the displayed number by another thousand
The only difference to me if that you're using a default property (Value) of the range in the second case, which, IMO, is only a venial sin.

I take it one step further and use this:

Code:
Function Cat(vInp As Variant, _
             Optional sSep As String = ",", _
             Optional bCatEmpty As Boolean = False) As String
    ' Catenates the elements of vInp separated by sSep
    ' Empty values and null strings are ignored unless bCatEmpty is True
 
    Dim vItem       As Variant
    Dim sItem       As String
 
    If bCatEmpty Then
        For Each vItem In vInp
            Cat = Cat & CStr(vItem) & sSep
        Next vItem
 
    Else
        For Each vItem In vInp
            sItem = CStr(vItem)
            If Len(sItem) Then Cat = Cat & sItem & sSep
        Next vItem
    End If
 
    If Len(Cat) Then Cat = Left(Cat, Len(Cat) - Len(sSep))
End Function
 
Upvote 0
shg4421,

Thanks shg4421. That's great. So I guess if one wants to "go by the book" one should state the Value property for the range object explicitly, right? Also, I like your version, which deals with empty/null strings.

Ruddles,

For sure... I did test it, and it seemed to work fine. I just wanted to make sure that I wasn't missing something. Thanks Ruddles.
 
Upvote 0
Yes indeed - I tend to mistrust most of the things I read on the Internet until I've tested them!
 
Upvote 0
Domenic said:
... one should state the Value property for the range object explicitly, right?
I mostly avoid using default properties as a matter of practice, but sometimes it's just too convenient not to. I always use
Code:
myRng(1,2)
in preference to
Code:
myRng.Item(1,2)
... for example.
 
Upvote 0
shg4421, Ruddles,

Thank you very much! I really appreciate your help!
 
Upvote 0
1) If Harlan wrote something there is probably a very good reason why.

2) If IsArray returns true for a Range, then either it's improperly named or incorrectly written.

3) If a is an array or a collection, I would recursively call AConcat since there is no way of knowing the content of each element.

4) I would definitely not rely on Value being the default property. It's a prescription for a disaster, if not now then in the future.

Here's Harlan Grove's custom function, which concatenates values within a range or array...

Code:
Function AConcat(a As Variant, Optional sep As String = "") As String
' Harlan Grove, Mar 2002

    Dim y As Variant

    If TypeOf a Is Range Then
    
        For Each y In a.Cells
            AConcat = AConcat & y.Value & sep
        Next y
    
    ElseIf IsArray(a) Then
    
        For Each y In a
            AConcat = AConcat & y & sep
        Next y
        
    Else
    
        AConcat = AConcat & a & sep
    
    End If
    
    AConcat = Left(AConcat, Len(AConcat) - Len(sep))
    
End Function

As you can see, it first tests for a range and then for an array. Since the IsArray function returns True for both a range and array, is there any reason why the code cannot be re-written as follows?

Code:
Function AConcat(a As Variant, Optional sep As String = "") As String

    Dim y As Variant

    If IsArray(a) Then
    
        For Each y In a
            AConcat = AConcat & y & sep
        Next y
    
    Else
    
        AConcat = AConcat & a & sep
    
    End If
    
    AConcat = Left(AConcat, Len(AConcat) - Len(sep))
    
End Function
 
Upvote 0
4. I would definitely not rely on Value being the default property. It's a prescription for a disaster, if not now then in the future.
It would certainly be a disaster for Microsoft; 10 million users would have their heads on a pike.
 
Upvote 0

Forum statistics

Threads
1,223,911
Messages
6,175,337
Members
452,637
Latest member
Ezio2866

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top