0

次の数値 (曜日を表す) が与えられた場合: 1,2,3,4,5,6,7.

いくつかの組み合わせの例と、それらの望ましい出力を次に示します。

  • 1,2,3,5,6,7->1-3,5-7
  • 1,3,5,7->1,3,5,7
  • 1,2,5,6->1,2,5,6
  • 1,2,3,6,7->1-3,6,7

アイデアは、連続する 3 日以上が範囲になり、1 日またはそれ以降の日は別々にレンダリングされるということです (または、2 から始まる範囲を作成する方が適切です)。

複雑な ed 関数をどこから始めればよいのかわかりませんか、ifそれとも LINQ 関数の 1 つを使用してこれを行うことができますか?
ジューシーな提案はありますか?

範囲の概念を単純化するために数値を使用しましたが、私のコードでは、次のように宣言されたフラグ付き列挙型があります。

[Flags]
public enum DaysOfWeek
{
  Sunday = 0x1,
  Monday = 0x2,
  Tuesday = 0x4,
  Wednesday = 0x8,
  Thursday = 0x10,
  Friday = 0x20,
  Saturday = 0x40
}

このエンティティの時間範囲 (別のプロパティで定義) が適用される曜日OpeningTimesを示す fieldを持つエンティティがあります。DaysOfWeek

したがって、私が使用する上記を取得します (実際にSelectインデックス + 1 を使用して追加する数値を取得するため):

var days = Enum.GetValues(typeof(DaysOfWeek))
             .Cast<DaysOfWeek>()
             .Where(dow => Model.DaysOfWeek.HasFlag(dow));

アイデアは、最初に範囲内の数字を削除することだと思います。

前の値も受け取り、別の値型を返すことができる集計関数を探していると思うので、現在の値-1が前の値に等しい場合に関数を作成できます。範囲が連続しなくなるまで(または要素がそれ自体を表す場合)、次の値を待ちます。これは、最後の一括を匿名オブジェクトとして返し、新しい一括で作業を開始するときです。

次に、次のような書式設定関数を作成しますif (item.First != item.Last) string.Join("-", item.First, Item.Last);

4

3 に答える 3

1

これが私の見解です。(残念ながら、1 つのセクションの重複を防ぐことはできませんでした:

static IEnumerable<string> GetRange(IEnumerable<int> range)
{
    using(IEnumerator<int> iter = range.GetEnumerator())
    if(iter.MoveNext())
    {
        int last = iter.Current;
        int start = iter.Current;
        while(iter.MoveNext())
        {
            int curr = iter.Current;
            if (curr == last+1)
            {
                last = curr;
                continue;
            }
            // found gap
            if (start == last)   // one isolated value
            {
                yield return start.ToString();
            }
            else if (last - start == 1) // two in a row.
            {
                yield return start.ToString();
                yield return last.ToString();
            }
            else
            {
                yield return string.Format("{0}-{1}", start,last);
            }
            start = curr;
            last = curr;            
        }

        if (start == last)   // one isolated value
        {
            yield return start.ToString();
        }
        else if (last - start == 1) // two in a row.
        {
            yield return start.ToString();
            yield return last.ToString();
        }
        else
        {
            yield return string.Format("{0}-{1}", start,last);
        }
    }
}
于 2013-06-28T04:10:42.533 に答える
1

興味深い問題です。読みやすさのために、範囲を表すクラスを用意することにしました。

class NumberRange
{
    public int Start { get; set;}
    public int End { get; set;}
    public override string ToString() 
    {
        return Start == End ? Start.ToString() : String.Format("{0}-{1}",Start,End);
    }
} 

順序付き整数の IEnumerable を範囲の IEnumerable に変換する拡張メソッド:

public static IEnumerable<NumberRange> ToRanges(this IEnumerable<int> numbers)
{
    NumberRange currentRange = null;
    foreach(var number in numbers)
    {
        if (currentRange == null)
            currentRange = new NumberRange() { Start = number, End = number };
        else if (number == currentRange.End + 1)
            currentRange.End = number;
        else
        {
            yield return currentRange;
            currentRange = new NumberRange { Start = number, End = number };
        }
    }
    if (currentRange != null)
    {
        yield return currentRange;
    }
}

そして、それを使用して、範囲を取得し、必要に応じてフォーマットできます。

String.Join(",",
    new int[] { 1,2,3,5,7,8,9,11 }
        .ToRanges()
        .Select(r => r.ToString()))
于 2013-06-28T12:36:47.823 に答える
1

これが私が考えたことです:

void Main()
{
    Console.WriteLine(AggregateString(new int[]{1,2,3,5,6,7}));   //1-3,5-7
    Console.WriteLine(AggregateString(new int[]{1,3,5,7}));       //1,3,5,7
    Console.WriteLine(AggregateString(new int[]{1,2,5,6}));       //1,2,5,6
    Console.WriteLine(AggregateString(new int[]{1,2,3,6,7 }));    //1-3,6,7
}


string AggregateString(int[] ary)
{ 
    List<List<int>> result=new List<List<int>>();
    ary.Aggregate((m,n)=>
        {
            if(m == n-1)
            {
            if(result.LastOrDefault()!=null && result.LastOrDefault().Last() ==m)
                result.Last().Add(n);
            else
                result.Add(new List<int>{m,n}); 
            }
            else 
            {
              if(result.LastOrDefault()==null)
                  result.Add(new List<int>{m,n}); 
              else result.Add(new List<int>{n});
            }
            return n;
        }); 
     return string.Join(",", result.Select(s=>s.Count()>2?
                    string.Join("-",new string[]{s.First().ToString(),s.Last().ToString()}) :
                    string.Join(",",s.Select(x=>x.ToString()).ToArray())).ToArray());
}
于 2013-06-28T02:34:32.523 に答える