12

のようなページ番号を表す文字列があります1,2,3,4,8,9,10,15

1-4,8-10,15 つまり、順番に数字がハイフンで区切られ、順番に最小と最大の数字で囲まれているように表示されます。

連続してブレークする場合、範囲はコンマで区切られます。

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);
4

9 に答える 9

8

ループ内のループが物事をより混乱させていると思います。リスト全体を 1 回だけ反復する必要があるため、ループを 1 つだけ使用してみてください。

int start,end;  // track start and end
end = start = arr[0];
for (int i = 1; i < arr.Length; i++)
{
    // as long as entries are consecutive, move end forward
    if (arr[i] == (arr[i - 1] + 1))
    {
        end = arr[i];
    }
    else
    {
        // when no longer consecutive, add group to result
        // depending on whether start=end (single item) or not
        if (start == end)
            result += start + ",";
        else if (end == (start + 1))
            result += start + "," + end + ",";
        else
            result += start + "-" + end + ",";

        start = end = arr[i];
    }
}

// handle the final group
if (start == end)
    result += start;
else
    result += start + "-" + end;

デモ: http://ideone.com/7HdpS7

于 2012-11-29T14:46:05.393 に答える
5

少しの LINQ でこれが整理されます。

static IEnumerable<Tuple<int, int>> GetRanges(IEnumerable<int> source)
{
   bool started = false;
   int rangeStart = 0, lastItem = 0;

   foreach (int item in source)
   {
      if (!started)
      {
         rangeStart = lastItem = item;
         started = true;
      }
      else if (item == lastItem + 1)
      {
         lastItem = item;
      }
      else
      {
         yield return new Tuple<int, int>(rangeStart, lastItem);
         rangeStart = lastItem = item;
      }
   }

   if (started)
   {
      yield return new Tuple<int, int>(rangeStart, lastItem);
   }
}

static string FormatRange(Tuple<int, int> range)
{
   string format = (range.Item1 == range.Item2) ? "{0:D}" : "{0:D}-{1:D}";
   return string.Format(format, range.Item1, range.Item2);
}

string pageNos = "5,6,7,9,10,11,12,15,16";
int[] pageNumbers = Array.ConvertAll(pageNos.Split(','), Convert.ToInt32);
string result = string.Join(",", GetRanges(pageNumbers).Select(FormatRange));
于 2012-11-29T14:53:33.233 に答える
3
string pageNos = "5,6,7,9,10,11,12,15,16";
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]);
}

StringBuilder sb = new StringBuilder();
bool hyphenOpen = false;
for (int i = 0; i < arr.Length - 1; i++)
{
    if (arr[i] + 1 == arr[i+1])
    {
        if (!hyphenOpen)
        {
            hyphenOpen = true;
            sb.Append(arr[i] + "-");
        }
    }
    else
    {
        hyphenOpen = false;
        sb.Append(arr[i] + ",");
    }
}
sb.Append(arr[arr.Length-1]);
Console.WriteLine(sb.ToString());

これは長くて不格好ですが、うまくいきます。

PS - OP の元の string->int をそのまま残しました。よりクリーンな方法については、質問に関する JonB のコメントを参照してください。

于 2012-11-29T14:45:53.473 に答える
3

このメソッドを使用して、各グループがカスタムRangeクラスで表される隣接する数値グループを取得できます。

class Range
{
    public int? Start { get; set; }
    public int? End { get; set; }
}

private static IEnumerable<Range> getAdjacentRanges(IEnumerable<int> nums)
{
    var ranges = new List<Range>();
    if (!nums.Any())
        return ranges;

    var ordered = nums.OrderBy(i => i);
    int lowest = ordered.First();
    int last = lowest;
    ranges.Add(new Range { Start = lowest });

    foreach (int current in ordered)
    {
        lastRange = ranges[ranges.Count - 1];
        if (current > last + 1)
        {
            lastRange.End = last;
            ranges.Add(new Range { Start = current });
        }
        last = current;
    }

    return ranges;
}

残りは簡単です:

var arr = new[] { 1, 2, 3, 4, 8, 9, 10, 15 };
var ranges = getAdjacentRanges(arr)
    .Select(r => r.End.HasValue ? string.Format("{0}-{1}", r.Start, r.End) : r.Start.ToString());
Console.Write(string.Join(",", ranges));

出力:1-4,8-10,15

デモ

于 2012-11-29T15:51:58.350 に答える
1
public static string HyphenateRanges(this string input)
{
    if (string.IsNullOrEmpty(input))
    {
        return "";
    }

    var orderedDistinct = input.Split(',')
                                .Select(Int32.Parse)
                                .Distinct()
                                .OrderBy(x => x)
                                .ToArray();

    Func<int, int, string> replaceRangeValuesWithDash =
        (x, i) =>
        i == 0 || // first
        i == orderedDistinct.Length - 1 || // last
        orderedDistinct[i + 1] - orderedDistinct[i - 1] != 2 // not in a range
            ? x.ToString()
            : "-";

    var rangeValuesDashed = orderedDistinct
        .Select(replaceRangeValuesWithDash)
        .ToList();

    var extraDashesRemoved = rangeValuesDashed
        .Where((x, i) => i == 0 || rangeValuesDashed[i - 1] != x)
        .ToArray();

    var formattedString = String.Join(",", extraDashesRemoved)
                                .Replace(",-,", "-");

    return formattedString;
}
于 2012-11-29T20:11:09.913 に答える
1

List<Tuple<int, int>>これは、各非連続値とそれに続く連続値の数でを作成する別のソリューションです。これは、 を使用して文字列に変換されますstring.Join

string pageNos = "1,2,3,4,8,9,10,15";

// Get list of numbers as ints
var list = pageNos.Split(',').Select(i => Convert.ToInt32(i)).ToList();

// Get a list of numbers and ranges of consecutive numbers
var ranges = new List<Tuple<int, int>>();
int start = 0;

for (int i = 0; i < list.Count; i++)
{
    // First item always starts a new range
    if (i == 0)
    {
        start = list[i];
    }

    // Last item always ends the current range
    if (i == list.Count - 1)
    {
        if (list[i] == list[i - 1] + 1)
        {
            ranges.Add(new Tuple<int, int>(start, list[i] - start));
        }
        else
        {
            ranges.Add(new Tuple<int, int>(start, list[i - 1] - start));
            ranges.Add(new Tuple<int, int>(list[i], 0));
        }
    }

    // End the current range if nonsequential
    if (i > 0 && i < list.Count - 1 && list[i] != list[i - 1] + 1)
    {
        ranges.Add(new Tuple<int, int>(start, list[i - 1] - start));
        start = list[i];
    }
}

// Craete the result string
var result = string.Join(", ", ranges.Select(r => r.Item2 == 0 ? r.Item1.ToString() : string.Format("{0}-{1}", r.Item1, r.Item1 + r.Item2)));
于 2012-11-29T15:15:30.670 に答える
1

私はC#の人ではありませんが、ここで問題があると思います:

 if (arr[i] == (arr[j] - 1))
            result += arr[i].ToString() + "-" + arr[j].ToString();

結果にそれを追加しないでください。しかし、フラグを設定して (おそらくブール値)、カウントを開始したことを示します。

flag==ture で、数値が連続していない場合は、もちろん「-」を使用して結果に追加する必要があります。

于 2012-11-29T14:50:12.113 に答える