Reputation: 49
How can I find sequential numbers in a cell, and replace them with a range?
For example:
change:
1,3,5,15,16,17,25,28,29,31...
to:
1,3,5,15-17,25,28-29,31...
The numbers are already sorted, i.e. in increasing order.
Thanks.
Upvotes: 2
Views: 913
Reputation: 75870
Thought I'd try an all-formulae solution using Microsoft365's LET()
as a way to capture variables.
The below solution only counts 3+ consecutive numbers as ranges of numbers, not two.
Formula in B1
:
=LET(X,FILTERXML("<t><s>"&SUBSTITUTE(A1,",","</s><s>")&"</s></t>","//s"),Y,TRANSPOSE(FILTERXML("<t><s>"&SUBSTITUTE(A1,",","</s><s>")&"</s></t>","//s[preceding::*[1]+1=.][following::*[1]-1=.]")),SUBSTITUTE(TEXTJOIN(",",,FILTERXML("<t><s>"&TEXTJOIN("</s><s>",,IF(MMULT(--(X=Y),SEQUENCE(COUNTA(Y),,,0)),"-",X))&"</s></t>","//s[.*0=0 or (.='-' and preceding::*[1]*0=0)]")),",-,","-"))
Upvotes: 4
Reputation: 55682
An interesting question that I wanted to look at do without looping through a sequence (which would need sorting first) checking for sequential builds
This function
Union
to group consecutive rows togetherloop wasn't necessary, shorter version!
Function NumOut(strIn As String) As String
Dim rng1 As Range
Set rng1 = Range("A" & Join(Split(Application.Trim([a1]), ", "), ",A"))
'force the range into areas rather than cells
Set rng1 = Union(rng1, rng1)
NumOut = Replace(Replace(Replace(rng1.Address, "$A$", vbNullstring), ": ", "-"), ",", ", ")
End Function
Upvotes: 6
Reputation: 53126
While the given range/area based answer is interesting, it suffers from a couple of flaws:
Here's a basic array loop based method. It can handle long strings. In my testing it runs in about 1/3 the time. It also has the bonus of not requiring the input to be sorted
Function NumOut2(strIn As String) As String
Dim arrIn() As String
Dim arrBuckets() As Long
Dim i As Long
Dim InRange As Boolean
Dim mn As Long, mx As Long
arrIn = Split(strIn, ", ")
mn = arrIn(0)
mx = arrIn(0)
For i = 1 To UBound(arrIn)
If arrIn(i) < mn Then
mn = arrIn(i)
ElseIf arrIn(i) > mx Then
mx = arrIn(i)
End If
Next
ReDim arrBuckets(mn To mx)
For i = 0 To UBound(arrIn)
arrBuckets(arrIn(i)) = arrIn(i)
Next
NumOut2 = LBound(arrBuckets)
InRange = False
For i = LBound(arrBuckets) + 1 To UBound(arrBuckets)
If arrBuckets(i) > 0 Then
If arrBuckets(i) = arrBuckets(i - 1) + 1 Then
If InRange Then
Else
InRange = True
NumOut2 = NumOut2 & "-"
End If
Else
If InRange Then
NumOut2 = NumOut2 & arrBuckets(i - 1) & ", " & arrBuckets(i)
Else
NumOut2 = NumOut2 & ", " & arrBuckets(i)
End If
End If
Else
If InRange Then
NumOut2 = NumOut2 & arrBuckets(i - 1)
End If
InRange = False
End If
Next
End Function
Upvotes: 3