0

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

 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 属性)的最佳方法是什么,如下所示?如果 Number 属性中的差异 > 1,那么它是一个间隙,Number 应该在不同的组中。

第 1 组

行 = 1,编号 = 100f
行 = 1,编号 = 101f

第 2 组

行 = 1,编号 = 105f
行 = 1,编号 = 106f

第 3 组

行 = 2,编号 = 103f
行 = 2,编号 = 104f

基本上,如果 Gap > 1 那么它应该按 Line 在不同的组中。

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

4

1 回答 1

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如果这两个项目被认为是相邻的,或者false它们不是相邻的,则返回。如何确定有序集中的两个项目的顺序和邻接取决于您。

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

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

简单的!

于 2013-10-30T00:37:23.640 回答