确定List <t> </t>中的值跳转

时间:2012-06-07 12:05:28

标签: c# .net linq

我有一个班级:

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

}

我有一个名为List<ShipmentInformation>的{​​{1}}变量。

然后我做了:

Results

我现在的问题是,在每个分组项目中,我有各种ShipmentInformation,但起始编号可能不是x顺序。基于传入参数,x可以是300或200。为了说明我可以

  1. 开始= 1,结束= 300
  2. 开始= 301,结束= 600
  3. 开始= 601,结束= 900
  4. 开始= 1201,结束= 1500
  5. 开始= 1501,结束= 1800
  6. 因为我有这个跳转,所以我不能使用上面的循环来创建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中的第一个和最后一个项来使用它们的数据来填充该实例。

    我想要一些方法来识别300或200的跳转,并创建一个ShipmentInformation实例,以添加到FinalResults,其中数据是连续的。

    使用上面的示例,我将有2个ShipmentInformation实例,其开头为1,结束为900,另一个实例为1201开始和1800年结束

4 个答案:

答案 0 :(得分: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();

答案 1 :(得分: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循环中的内容。通过将其置于Select语句中来替换foreach循环,可以使其更加可怕,就像富人的回答一样。)

答案 2 :(得分: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);

答案 3 :(得分:0)

另一种LINQ解决方案是使用Except扩展方法。

编辑:用C#重写,包括将缺失的点组成回Ranges:

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; }

}