Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Separate range of numbers, if in sequence then by hyphen, and if break in sequence occurs then comma character

Tags:

c#

algorithm

I have a string denoting page nos like 1,2,3,4,8,9,10,15.

I want this to be shown as 1-4,8-10,15 i.e numbers in sequence are separated by hyphen enclosed by smallest and largest number in sequence.

If break in sequence, the range is to be separated by comma.

string pageNos = "5,6,7,9,10,11,12,15,16";
string result=string.Empty;
string[] arr1 = pageNos.Split(',');
int[] arr = new int[arr1.Length];

for (int x = 0; x < arr1.Length; x++) // Convert string array to integer array
{
    arr[x] = Convert.ToInt32(arr1[x].ToString());
}

for (int i = 0; i < arr.Length;i++)
{
    for (int j = i + 1; ; j++)
        if (arr[i] == (arr[j] - 1))
            result += arr[i].ToString() + "-" + arr[j].ToString();
        else
            result += arr[i].ToString() + ",";
}

Console.WriteLine(result);
like image 844
Mudassir Hasan Avatar asked Nov 29 '12 14:11

Mudassir Hasan


1 Answers

Use this helper class to convert back and forth between number lists and range strings.

This copies implementation of ConvertRangeStringToNumberList() from here and ConvertNumberListToRangeString() from here with slight improvements.

using System;
using System.Collections.Generic;
using System.Linq;

public static class NumberRangeHelper
{
    /// <summary>
    /// Converts a string of comma separated list of numbers and ranges to the list of individual numbers it represents.
    /// </summary>
    /// <param name="numbers">Range in form of <c>"2,4-8,11,15-22,39"</c></param>
    /// <returns>A list of numbers</returns>
    public static List<int> ConvertRangeStringToNumberList(string numbers)
    {
        var numbersSplit = numbers.Split(',');
        var convertedNumbers = new SortedSet<int>();
        foreach (var strNumber in numbersSplit)
        {
            int number;
            if (int.TryParse(strNumber, out number))
            {
                convertedNumbers.Add(number);
            }
            else
            {
                // try and delimited by range
                if (strNumber.Contains('-'))
                {
                    var splitRange = strNumber.Split('-');
                    if (splitRange.Length == 2)
                    {
                        int firstNumber;
                        int secondNumber;

                        if (Int32.TryParse(splitRange[0], out firstNumber) &&
                            Int32.TryParse(splitRange[1], out secondNumber))
                        {
                            for (var i = firstNumber; i <= secondNumber; ++i)
                            {
                                convertedNumbers.Add(i);
                            }
                        }
                    }
                }
            }
        }
        return convertedNumbers.ToList();
    }

    /// <summary>
    /// Converts a list of numbers to their concise range representation.
    /// </summary>
    /// <param name="numbers">A list of numbers such as <c>new[] { 1, 2, 3, 4, 5, 12, 13, 14, 19 }</c></param>
    /// <returns>A string like <c>"1-5, 12-14, 19"</c></returns>
    public static string ConvertNumberListToRangeString(IEnumerable<int> numbers)
    {
        var items = new SortedSet<int>(numbers)
            .Select((n, i) => new { number = n, group = n - i })
            .GroupBy(n => n.group)
            .Select(g => (g.Count() >= 3)
                    ? g.First().number + "-" + g.Last().number
                    : String.Join(", ", g.Select(x => x.number))
            )
            .ToList();

        return String.Join(", ", items);
    }

}

Test:

Action<IEnumerable<int>> DumpList = l => Console.WriteLine("\t[{0}]", String.Join(", ", l));
Action<string> DumpRange = s => Console.WriteLine("\t\"{0}\"", s);

var numbers = new[] { 1, 1, 2, 3, 4, 5, 12, 13, 19, 19, 6, 7 };
DumpList(numbers);
var str = ConvertNumberListToRangeString(numbers);
DumpRange(str);
var list = ConvertRangeStringToNumberList(str);
DumpList(list);

Console.WriteLine();    

str = "1-5, 12, 13, 19, 20, 21, 2-7";
DumpRange(str);
list = ConvertRangeStringToNumberList(str);
DumpList(list);
str = ConvertNumberListToRangeString(list);
DumpRange(str);

Output:

[1, 1, 2, 3, 4, 5, 12, 13, 19, 19, 6, 7]
"1-7, 12, 13, 19"
[1, 2, 3, 4, 5, 6, 7, 12, 13, 19]

"1-5, 12, 13, 19, 20, 21, 2-7"
[1, 2, 3, 4, 5, 6, 7, 12, 13, 19, 20, 21]
"1-7, 12, 13, 19-21"
like image 107
orad Avatar answered Oct 03 '22 06:10

orad