Last night, Shira posed me a spreadsheet quandary: how do you take a series of rows and combine them together into a single cell (say, comma separated)? After looking around, I realized that there wasn't a built in function that would do this. transpose will turn rows in columns, but it doesn't join items up in a single cell. To get this job done, I was going to have to turn to VB. Gulp.
I knew how I wanted the function work, it should behave like countif. That is, I didn't want it to combine every cell in a range, only those that matched some criteria.
Why Excel offers countif and sumif but doesn't offer concatenateif is beyond me. But, luckily it wasn't beyond MikeRickson over at ozgrid.com. He and a couple other folks provided me with a bunch of wonderful useful bits of knowledge:
1. An implementation of >concatenateif(...):
Function concatenateIf(ByVal compareRange As Range, _ ByVal criteriaEQ As Variant, _ ByVal stringsRange As Range, _ Optional Delimiter As String, _ Optional Unique As Boolean) As String Dim stringsRRay As Variant Dim compRRay As Variant Dim i As Long, j As Long Set compareRange = Application.Intersect(compareRange, _ compareRange.Parent.UsedRange) compRRay = compareRange.Value stringsRRay = compareRange.Offset(stringsRange.Row - compareRange.Row, _ stringsRange.Column - compareRange.Column).Value Select Case TypeName(compRRay) Case "Variant()" concatenateIf = Delimiter For i = 1 To UBound(compRRay, 1) For j = 1 To UBound(compRRay, 2) If compRRay(i, j) = criteriaEQ Then If Unique Imp (InStr(concatenateIf, Delimiter & CStr(stringsRRay(i, j)) & Delimiter) = 0) Then concatenateIf = concatenateIf & CStr(stringsRRay(i, j)) & Delimiter End If End If Next j Next i concatenateIf = Left(concatenateIf, Len(concatenateIf) - Len(Delimiter)) concatenateIf = Mid(concatenateIf, Len(Delimiter) + 1) Case "Double", "String", "Boolean": Rem cell.count = 1 If compRRay = criteriaEQ Then concatenateIf = CStr(stringsRRay) Case Else concatenateIf = TypeName(compRRay) End Select End Function
2. A simpler concat function which dispenses with the criteria concept:
Function Concat(r As Range) As String Dim av As Variant Dim v As Variant av = Intersect(r, ActiveSheet.UsedRange) For Each v In av If Not IsEmpty(v) Then Concat = Concat & v & "," End If Next Concat = Left(Concat, Len(Concat) - 1) End Function
3. Instructions on how to set these functions up.
[The code] needs to be posted in a code module. Open the VBE (Alt+F11), and from that menu bar, do Insert > Module, and paste the code into the window that opens.
Besides providing some useful code, this forum post showed me just how easy it is to add new functions to Excel. I've written VB code before, but it's usually as a stand alone app, and not something that truly leverages the existing Excel model.
I can't remember the last time such a brief forum post was so enlightening.
With the above code in place I was able to say:
=concatenateif(A:A, "=100", C:C, ", ")
(Where column A (A:A) contained a bunch of numbers, and column C contained the text I wanted to join up with ", ".)
No comments:
Post a Comment