4

私はクラスを持っています:

public class ShipmentInformation
{
    public string OuterNo { get; set; }
    public long Start { get; set; }
    public long End { get; set; }

}

というList<ShipmentInformation>変数がありますResults

次に、次のことを行います。

List<ShipmentInformation> FinalResults = new List<ShipmentInformation>();
var OuterNumbers = Results.GroupBy(x => x.OuterNo);
foreach(var item in OuterNumbers)
{
   var orderedData = item.OrderBy(x => x.Start);

   ShipmentInformation shipment = new ShipmentInformation();
   shipment.OuterNo = item.Key;
   shipment.Start = orderedData.First().Start;
   shipment.End = orderedData.Last().End;

   FinalResults.Add(shipment);
}

私が今抱えている問題は、グループ化された各アイテム内にさまざまなShipmentInformationがありますが、開始番号がxで連続していない可能性があることです。xは、着信パラメータに基づいて300または200にすることができます。説明するために私は持つことができます

  1. 開始=1、終了= 300
  2. 開始=301、終了= 600
  3. 開始=601、終了= 900
  4. 開始=1201、終了= 1500
  5. 開始=1501、終了= 1800

このジャンプがあるため、上記のループを使用してのインスタンスを作成しShipmentInformation、最初と最後のアイテムを取り込んで、orderedDataそれらのデータを使用してそのインスタンスにデータを入力することはできません。

300または200のジャンプを識別し、ShipmentInformationのインスタンスを作成して、データが連続しているFinalResultsに追加する方法が必要です。

上記の例を使用すると、開始が1で終了が900のShipmentInformationのインスタンスが2つあり、開始が1201で終了が1800の別のインスタンスがあります。

4

4 に答える 4

4

次のことを試してください。

private static IEnumerable<ShipmentInformation> Compress(IEnumerable<ShipmentInformation> shipments) 
{
  var orderedData = shipments.OrderBy(s => s.OuterNo).ThenBy(s => s.Start);
  using (var enumerator = orderedData.GetEnumerator())
  {
    ShipmentInformation compressed = null;
    while (enumerator.MoveNext())
    {
      var current = enumerator.Current;
      if (compressed == null) 
      {
        compressed = current;
        continue;
      }
      if (compressed.OuterNo != current.OuterNo || compressed.End < current.Start - 1)
      {
        yield return compressed;
        compressed = current;
        continue;
      }
      compressed.End = current.End;
    }

    if (compressed != null)
    {
      yield return compressed;
    }
  }
}

そのように使用可能:

var finalResults = Results.SelectMany(Compress).ToList();
于 2012-06-07T12:21:50.770 に答える
1

恐らくひどいパフォーマンスを持ち、理解することが不可能であるが、すぐに使えるLINQのみを使用するものが必要な場合は、これでうまくいくと思います。

var orderedData = item.OrderBy(x => x.Start);
orderedData
    .SelectMany(x => 
        Enumerable
            .Range(x.Start, 1 + x.End - x.Start)
            .Select(n => new { time = n, info = x))
    .Select((x, i) => new { index = i, time = x.time, info = x.info } )
    .GroupBy(t => t.time - t.info)
    .Select(g => new ShipmentInformation {
        OuterNo = g.First().Key,
        Start = g.First().Start(),
        End = g.Last().End });

脳が痛い。

(わかりやすくするために編集してください。これはループ内にあるものを置き換えるだけです。リッチの回答のように、これをステートメントforeach内に入れてループを置き換えることで、さらに恐ろしいものにすることができます。)Selectforeach

于 2012-06-07T12:25:36.670 に答える
1

これはどう?

List<ShipmentInfo> si = new List<ShipmentInfo>();
si.Add(new ShipmentInfo(orderedData.First()));
for (int index = 1; index < orderedData.Count(); ++index)
{
    if (orderedData.ElementAt(index).Start == 
        (si.ElementAt(si.Count() - 1).End + 1))
    {
        si[si.Count() - 1].End = orderedData.ElementAt(index).End;
    }
    else
    {
        si.Add(new ShipmentInfo(orderedData.ElementAt(index)));
    }
}

FinalResults.AddRange(si);
于 2012-06-07T12:42:50.763 に答える
0

別のLINQソリューションは、Except拡張メソッドを使用することです。

編集:C#で書き直され、欠落しているポイントを範囲に戻すことを含みます:

class Program
{
    static void Main(string[] args)
    {

        Range[] l_ranges = new Range[] { 
            new Range() { Start = 10, End = 19 },
            new Range() { Start = 20, End = 29 },
            new Range() { Start = 40, End = 49 },
            new Range() { Start = 50, End = 59 }
        };

        var l_flattenedRanges =
            from l_range in l_ranges
            from l_point in Enumerable.Range(l_range.Start, 1 + l_range.End - l_range.Start)
            select l_point;

        var l_min = 0;
        var l_max = l_flattenedRanges.Max();

        var l_allPoints =
            Enumerable.Range(l_min, 1 + l_max - l_min);

        var l_missingPoints =
            l_allPoints.Except(l_flattenedRanges);

        var l_lastRange = new Range() { Start = l_missingPoints.Min(), End = l_missingPoints.Min() };
        var l_missingRanges = new List<Range>();

        l_missingPoints.ToList<int>().ForEach(delegate(int i)
        {
            if (i > l_lastRange.End + 1)
            {
                l_missingRanges.Add(l_lastRange);
                l_lastRange = new Range() { Start = i, End = i };
            }
            else
            {
                l_lastRange.End = i;
            }
        });
        l_missingRanges.Add(l_lastRange);

        foreach (Range l_missingRange in l_missingRanges) {
            Console.WriteLine("Start = " + l_missingRange.Start + " End = " + l_missingRange.End);
        }

        Console.ReadKey(true);
    }
}

class Range
{

    public int Start { get; set; }
    public int End { get; set; }

}
于 2012-06-07T12:40:06.430 に答える