OrderBy ThenBy - 捕捉剩余(平等)物品的最简单方法?

时间:2016-06-15 13:33:48

标签: c# linq

请考虑以下事项:

new[] {
    new { A = 3, B = 3 },
    new { A = 2, B = 2 },
    new { A = 2, B = 2 },
    new { A = 1, B = 1 }
}
.OrderBy(x => x.A)
.ThenBy(x => x.B)
.ToList();

List将按以下顺序包含以下数据:

  

[{A = 1,B = 1},{A = 2,B = 2},{A = 2,B = 2},{A = 3,B = 3}]

如何确定项12相等?我想要'当所有throw / OrderBy语句执行且仍有相同的项目(无法排序)时,我的代码ThenBy

注意,想象这些项目非常复杂(具有很多属性),并且有一百万个OrderBy / ThenBy语句,以及一个很多数据。我宁愿避免再次迭代数据。

2 个答案:

答案 0 :(得分:3)

您可以在之前进行排序。识别重复项的最简单方法是使用FormHome

由于您使用匿名类型,因此您可以按项目本身进行分组:

GroupBy

如果您不在现实中使用匿名类型,那么只需按照您要用来定义"相等的属性进行分组。

您还可以检查连续重复"内联"使用扩展方法:

var data = 
    new[] {
        new { A = 3, B = 3 },
        new { A = 2, B = 2 },
        new { A = 2, B = 2 },
        new { A = 1, B = 1 }
    };

var groups = data.GroupBy(x => x); // works since we are using anonymous types that use value equality

if(groups.Any(g => g.Count() > 1)
{
   // throw exception
}

var result = groups.Select(g=>g.Key)
                   .OrderBy(x => x.A)
                   .ThenBy(x => x.B)
                   .ToList();

public static IEnumerable<T> ThrowIfConsecutiveItemsAreEqual<T>(this IEnumerable<T> source) { bool isFirst = true; T prev = default(T); foreach(var item in source) { if(!isFirst && item.Equals(prev)) throw new Exception(); // TODO: use a better exception type and message yield return item; isFirst = false; prev = item; } } 之前调用扩展方法以避免多次枚举:

ToList

答案 1 :(得分:0)

为了以这种方式查找重复项,您只需要在排序后查看上一项:

static IEnumerable<C> Deduplicate(this IEnumerable<C> items) {
 C last = null;
 foreach (var item in items) {
  if (last != null && last.A == item.A && last.B == item.B) {
   //duplicate, handle as you like
  }

  last = item;
  yield return item;
}

有各种方法来分解这种逻辑,但这是基本的想法。我发现编写一个帮助迭代器会很有用,它会返回相同的序列,但每个项目的前一个项目。使用该帮助程序,您不再需要编写自定义迭代器。