从没有间隙的对象列表中获取范围:

时间:2013-10-29 23:37:29

标签: c# .net linq

给出列表中包含数千个对象的列表,如下所示:

 var list = new List<PointAddress>();
 list.Add(new PointAddress { Line = 1, Number = 100f });
 list.Add(new PointAddress { Line = 1, Number = 101f });
 list.Add(new PointAddress { Line = 1, Number = 105f });
 list.Add(new PointAddress { Line = 1, Number = 106f });
 list.Add(new PointAddress { Line = 2, Number = 103f });
 list.Add(new PointAddress { Line = 2, Number = 104f });

创建无间隙范围(基于Number属性)的最佳方法是什么,如下所示? 如果差异>数字属性中的1是间隙,数字应该在不同的组中。

第1组

Line = 1,Number = 100f
  Line = 1,Number = 101f

第2组

Line = 1,Number = 105f
  Line = 1,Number = 106f

第3组

Line = 2,Number = 103f
  Line = 2,Number = 104f

基本上如果Gap&gt; 1然后它应该在Line的不同组中。

如果该行不同,则它是不同的组。如果Number是相邻的数字且Line是相同的,那么它必须在示例中所示的同一组中。第1行分为2组 - 第1组和第2组,因为数字不相邻。

1 个答案:

答案 0 :(得分:2)

假设您的列表已订购,则以下内容应该有效。

首先,一个简单的通用Linq扩展来对列表进行分区:

public static IEnumerable<List<T>> Partition<T>( this IEnumerable<T> source , Func<T,T,bool> areAdjacent )
{
  List<T> list = null ;
  T       prev = default(T) ;

  foreach ( T curr in source )
  {
    if ( list == null )
    {
      list = new List<T> {curr} ;
    }
    else if ( areAdjacent(prev,curr) )
    {
      list.Add(curr) ;
    }
    else
    {
      yield return list ;
      list = new List<T> {curr} ;
    }

    prev = curr ;
  }

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

}

然后你可以调用它

List<PointAddress> addressList = GetSomeEnormousList() ;

List<List<PointAddress>> ranges = addressList
                                  .Partition( (prev,curr) => curr.Line == prev.Line && curr.Number - prev.Number == 1.0 )
                                  .ToList()
                                  ;

你需要的只是一个lambda,它将获取两个PointAddress项并比较它们以确定是否存在序列中断,如果认为这两个项是相邻的,则返回true或{{ 1}}如果他们不是。如何确定订单中的订单和邻接两个项目取决于您。

如果您的列表无序,您可以订购:

false

容易!