integer() to CSV string with runs

I’m trying to convert any sorted (ascending) list of positive integers into a string of comma-separated values, including shorthand for “runs” of consecutive numbers more than 2 numbers long. A few examples:

Array( 1, 3, 5, 7, 8, 9 ) = “1,3,5,7-9”
Array( 4, 5, 11, 12, 15, 16, 17 ) = “4,5,11,12,15-17”
Array( 1, 2, 3, 4, 5, 6, 8, 11, 12, 23, 24, 25 ) = “1-6,8,11,12,23-25”

The string without runs is obviously very easy. Here’s my code that doesn’t work. It started out simply and I kept piling on more things. It’s obviously wrong logic, but I’m having trouble thinking in another way. Any help?

// a sorted integer array i() is given
' go through and remove indexes within a run
' look at 2 at a time and don't mark runs that are only 2 numbers long
dim j, n, thisA, thisB, lastValue as integer
dim r(), final as string
r.append str( i(0) )
lastValue = i(0)
j = 1
while j < i.Ubound
  thisA = i(j)
  thisB = i(j+1)
  if thisA = lastValue + 1 and thisB = lastValue + 2 then
    // RUN OF 2
    if j = i.Ubound - 1 then
      r.append "-"
      r.append str( thisB )
    else
      r.append "-"
      lastValue = thisB
    end if
    j = j + 2
    
  elseif thisA = lastValue + 1 then
    // RUN OF 1
    if j = i.Ubound - 1 then
      r.append str( thisA )
      r.append str( thisB )
    else
      r.append str( thisA )
      lastValue = thisA
    end if
    j = j + 1
    
  else
    // NO RUN
    if j = i.Ubound - 1 then
      r.append str( thisA )
      r.append str( thisB )
    else
      r.append str( thisA )
      lastValue = thisA
    end if
    j = j + 1
    
  end if
  
wend
' always append the last value of an odd array (wrong)
if j = i.Ubound then r.append str( i(j) )

' horrible
final = ReplaceAll( join( r(), "," ), "-,-", "-" )
while instr( final, "-,-" ) > 0
  final = ReplaceAll( final, "-,-", "-" )
wend
final = ReplaceAll( final, ",-,", "-" )
return final

quickly banged this out
its like RLE encoding :slight_smile:

Public Function ToArrayString(values() as integer) as string
  Dim runStarts() As Integer
  Dim runLengths() As Integer
  
  For i As Integer = 0 To values.ubound
    If i = 0 Then
      runStarts.Append i
      runlengths.append 1
      Continue
    End If
    
    If values(i) = values(runstarts(runstarts.ubound) + runLengths(runlengths.ubound) - 1) + 1 Then
      runlengths(runLengths.ubound) = runlengths(runLengths.ubound) + 1
      Continue
    End If
    
    runstarts.append i
    runLengths.append 1
  Next
  
  Dim result As String
  
  // now walk the starts And lengths To assemble our String
  For i As Integer = 0 To runStarts.ubound
    
    Dim startValue As Integer = values(runStarts(i))
    Dim runLength As Integer = runLengths(i)
    
    If result <> "" Then
      result = result + "," 
    End If
    
    If runLength = 1 Then
      result = result + Str(startValue)
      
    Elseif runlength = 2 Then
      result = result + Str(startValue) + "," + Str(startValue+1)
      
    Else
      result = result + Str(startValue) + "-" + Str(startValue+runlength-1)
      
    End If
    
  Next
  
  Return result
End Function

tested with your code

Dim s As String 
s = ToArrayString( Array( 1, 3, 5, 7, 8, 9 )) 
If s <>  "1,3,5,7-9" Then
  Break
End If

s = ToArrayString( Array( 4, 5, 11, 12, 15, 16, 17 )) 
If s <> "4,5,11,12,15-17" Then
  Break
End If

s = ToArrayString( Array( 1, 2, 3, 4, 5, 6, 8, 11, 12, 23, 24, 25 )) 
If s <> "1-6,8,11,12,23-25"  Then
  Break
End If

[code]Public Function ToArrayString(values() As Integer) As String

Var lastIndex, lastIndexMinus1 As Integer
lastIndex = values.LastRowIndex
lastIndexMinus1 = lastIndex - 1

Var finalString As String = “”
finalString = Str(values(0))

For i As Integer = 1 To lastIndexMinus1

If values(i) = values(i - 1) + 1 And values(i) = values(i + 1) - 1 Then
finalString = finalString + “-”
Else
finalString = finalString + “,” + Str(values(i))
End If

Next

finalString = finalString + “,” + Str(values(lastIndex))

finalString = finalString.ReplaceAll("-,", “-”)
While finalString.IndexOf("–") <> -1
finalString = finalString.ReplaceAll("–", “-”)
Wend

Return finalString

End Function[/code]

This was my approach:

Public Function ArrayToRange(a() As Integer) as String
  if a.Ubound = -1 then return "" 'Bail out if null array
  dim outList,seqDelimiter As String = ""
  dim runCount As integer = 0
  dim seqFlag As Boolean = false
  for i as Integer = 0 to a.Ubound-1
    if seqFlag and (a(i)<>a(i+1)-1) then 'Is this end of sequence?
      outList = outList+seqDelimiter 'Yes, so add sequence delimiter
      seqFlag = False 'reset flag and runCount
      runCount = 0
    end if
    if not seqFlag then  'Is sequence in progress?
      outList = outList+str(a(i)) 'No, so append the current value
    end if
    if a(i)=(a(i+1)-1) then 'Is this start or continuation of sequence?
      seqFlag = true
      runCount = runCount+1
      seqDelimiter = if(runCount>1,"-",",")
    Else 'Sequence not in progress
      outList = outList+"," 'append a comma
    end if
  next
  'Append last value and return
  return outList+if(seqFlag,seqDelimiter,"")+str(a(a.Ubound))
End Function

Thank you guys! It is so nice to be able to get help here from people who are smarter than me!

Each solution works, obviously each differently, and I like each one for different reasons. The one closest to what I was originally going for is from Robert Livingston (which also makes me a little proud — inelegant string replacing at the end notwithstanding — since it’s also the shortest of the three posted answers :slight_smile: ). Somehow I took a wrong turn and my code kept growing with more and more errors in it. Here’s my version of his code which I converted to the old API: