dcsimg
Results 1 to 7 of 7

Thread: [RESOLVED] String of Numbers to Range of Numbers

  1. #1

    Thread Starter
    Lively Member dprontnicki's Avatar
    Join Date
    Sep 2016
    Posts
    84

    Resolved [RESOLVED] String of Numbers to Range of Numbers

    Hi, I am hoping someone can help with this or point me in the right direction. I have tried searching the site but could not find anything similar and didn't know exactly how to search this. So I apologize if this has been discussed/answered already.

    I have a sub that will generate a string of numbers separated by a comma. I would like a function that will combine the numbers into ranges of numbers with a hyphen. Ex:

    Generated from sub:
    501-510, 1232, 1233, 1234, 367, 366, 365, 50-52, 893, 897, 1104

    Function Output:
    50-52, 365-367, 501-510, 893, 897, 1104, 1232-1234

    The original numbers and combination (Generated from Sub) could be any amount of numbers and in any combination. The number will always be whole numbers and always positive. The function should put them in an order like the Function output numbers above.

    I hope this makes sense, Thank you.

  2. #2
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,098

    Re: String of Numbers to Range of Numbers

    You can use stringVariable.Split() to convert the string into an array of strings (use "," as the separator).


    One way would be to make a boolean array which has enough elements for all of the numbers (so for your example data, the array would have an upperbound of at least 1234).

    Once you have that, read thru the items and set the boolean values in the array to True when a single value is found (so for 1232 set booleanArray(1232)=True ), and for ranges use a For loop to set the values to True.

    When that is done you can loop the boolean array to find items that are set, and build the string accordingly. When you find a True in the array, that number should be part of the output - but if the next item is also true you need to display a range.


    Of course it would be easier if the original sub generated the boolean array instead (or even better a List(Of Integer) ), but that might not be viable in your circumstances.

  3. #3

    Thread Starter
    Lively Member dprontnicki's Avatar
    Join Date
    Sep 2016
    Posts
    84

    Re: String of Numbers to Range of Numbers

    You can use stringVariable.Split() to convert the string into an array of strings (use "," as the separator). OK I understand and can do this.


    One way would be to make a boolean array which has enough elements for all of the numbers (so for your example data, the array would have an upperbound of at least 1234). I have never worked with boolean arrays before. I understand the concept and what you are saying just wouldn't know how to initiate.

    Once you have that, read thru the items and set the boolean values in the array to True when a single value is found (so for 1232 set booleanArray(1232)=True ), and for ranges use a For loop to set the values to True. Makes sense but again would not know how to initiate.

    When that is done you can loop the boolean array to find items that are set, and build the string accordingly. When you find a True in the array, that number should be part of the output - but if the next item is also true you need to display a range. OK, I understand the concept and what you are saying but again..


    Of course it would be easier if the original sub generated the boolean array instead (or even better a List(Of Integer) ), but that might not be viable in your circumstances. I could convert the string to List(of Integer) before sending to the function if that truly would make it easier. I do not believe that it will affect the sub in anyway.

  4. #4
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,098

    Re: String of Numbers to Range of Numbers

    Converting from strings to numbers is mandatory in order to build the output you want (without it, you wouldn't be able to get 365-367), it's just a matter of where that conversion happens.


    After I posted I realised that just using a List(of Integer) would be best, as it simplifies the design and probably memory usage too.

    When you have the source items Split, you can add them to the list - for a single number just add the number, if it is a range like 501-510 then use a For loop to add all the items in the range.

    You can then sort the list, and build the output string you want based on the items in it. If the next number is one higher than the current number then they are both part of a range, otherwise the current number is just a single number (or the end of a range). Use appropriate variables to determine if you are currently in a range, and which number the range started with.

  5. #5

    Thread Starter
    Lively Member dprontnicki's Avatar
    Join Date
    Sep 2016
    Posts
    84

    Re: String of Numbers to Range of Numbers

    OK, so I got it working. I think I did it the way you explained. I took a two prong approach using two separate functions. If this could be simplified I would love to know how. The first function will get all the numbers like you suggested, split the ranges, and put them in acceding order.

    The second function will then take the sorted numbers and place them back into a ranged format. I then, back in the sub, take the new list and join to a new string.

    Get the Point Numbers, separate and place in order:
    Code:
        Public Function ToSortedListOfPointNumbers(ByVal pointNumbers As String)
    
            Dim pointNumberList As New List(Of Integer)
    
            For Each pointNumber As String In pointNumbers.Split(","c)
    
                If pointNumber.Contains("-"c) Then
    
                    Dim firstNumber As Integer = Convert.ToInt32(pointNumber.Split("-"c)(0))
    
                    Dim lastNumber As Integer = Convert.ToInt32(pointNumber.Split("-"c)(1))
    
                    For pn As Integer = firstNumber To lastNumber
    
                        pointNumberList.Add(pn)
    
                    Next
    
                Else
    
                    pointNumberList.Add(Convert.ToInt32(pointNumber))
    
                End If
    
            Next
    
            Dim sortedPointNumberList As List(Of Integer) = pointNumberList.OrderBy(Function(number) number).ToList()
    
            Return sortedPointNumberList
    
        End Function
    Take Sorted Point Numbers and place into ranged groups
    Code:
        Function ToRangesOfPointNumbers(ByVal sortedPointNumberList As List(Of Integer)) As String()
    
            If sortedPointNumberList.Count < 1 Then Return New String() {}
    
            Dim numberOfPoints = sortedPointNumberList.Count
            Dim startNumbers = New List(Of Integer)()
            Dim endNumbers = New List(Of Integer)()
    
            For i = 0 To numberOfPoints - 1 - 1
    
                If i = 0 Then startNumbers.Add(sortedPointNumberList(0))
    
    
                If sortedPointNumberList(i + 1) > sortedPointNumberList(i) + 1 Then
    
                    endNumbers.Add(sortedPointNumberList(i))
    
                    startNumbers.Add(sortedPointNumberList(i + 1))
    
                End If
    
            Next
    
            endNumbers.Add(sortedPointNumberList(numberOfPoints - 1))
    
            Return Enumerable.Range(0, endNumbers.Count).[Select](Function(i) startNumbers(i).ToString() + (If(endNumbers(i) = startNumbers(i), "", "-" & endNumbers(i).ToString()))).ToArray()
    
        End Function
    In sub to final result of updatedIncludedPointNumbers
    Code:
    Dim sortedPointNumbers = ToSortedListOfPointNumbers(includedNumbers & "," & cogoPointsToAdd)
    
    Dim rangedPointNumbers = ToRangesOfPointNumbers(sortedPointNumbers)
    
    Dim updatedIncludedPointNumbers As String = String.Join(",", rangedPointNumbers.ToArray)
    What do you think? I feel this could be simplified, but I have tunnel vision now and cant seem to see it. I will play with it over the weekend but any pointers or suggestions are very welcome.

  6. #6
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,098

    Re: [RESOLVED] String of Numbers to Range of Numbers

    That looks good

    In ToSortedListOfPointNumbers, I would change this section:
    Code:
                    Dim firstNumber As Integer = Convert.ToInt32(pointNumber.Split("-"c)(0))
    
                    Dim lastNumber As Integer = Convert.ToInt32(pointNumber.Split("-"c)(1))
    
                    For pn As Integer = firstNumber To lastNumber
    ...to:
    Code:
                    Dim rangeNumbers As String = pointNumber.Split("-"c)
    
                    For pn As Integer = Convert.ToInt32(rangeNumbers(0)) To Convert.ToInt32(rangeNumbers(1))
    This should run slightly faster (as the complex split only happens once), and takes a little less code.

    Note however that this section won't cope with negative numbers (due to the - character), so will need some extra work if you think you might ever need to deal with them.


    In ToRangesOfPointNumbers I would change this:
    Code:
            For i = 0 To numberOfPoints - 1 - 1
    
                If i = 0 Then startNumbers.Add(sortedPointNumberList(0))
    to:
    Code:
            startNumbers.Add(sortedPointNumberList(0))
    
            For i = 0 To numberOfPoints - 1 - 1
    ...because you have already checked that sortedPointNumberList contains at least one item.


    There isn't really much scope to simplify these routines, but if you could modify the original sub the data comes from (so that it returns a List(of Integer)) then that would simplify the process as it would reduce ToSortedListOfPointNumbers to just the OrderBy line.

  7. #7

    Thread Starter
    Lively Member dprontnicki's Avatar
    Join Date
    Sep 2016
    Posts
    84

    Re: [RESOLVED] String of Numbers to Range of Numbers

    Thank so much! I got a little help from "the great white box of hope" (Google). Once you explained how to approach it, it was easier to search for what I was looking for. I will defiantly be incorporating your suggestions. And there should never be negative numbers as these represent survey point numbers which are always positive. So I should be good. (Famous last words)

    Thank you again so much!!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width