What#39;s a good, generic algorithm for collapsing a set of potentially-overlapping ranges?(用于折叠一组可能重叠的范围的好的通用算法是什么?)
问题描述
我有一个方法可以获取这个类的一些对象
I have a method that gets a number of objects of this class
class Range<T>
{
public T Start;
public T End;
}
在我的例子中,T
是 DateTime
,但为了简单起见,我们使用 int
.我想要一种将这些范围折叠成覆盖相同区域"但不重叠的方法.
In my case T
is DateTime
, but lets use int
for simplicity. I would like a method that collapses those ranges into ones that cover the same "area" but that do not overlap.
如果我有以下范围
- 1 到 5
- 3 到 9
- 11 至 15
- 12 至 14
- 13 到 20
方法应该给我
- 1 到 9
- 11 至 20
猜猜它会被称为工会?我想方法签名可能看起来像这样:
Guess it would be called a union? I imagine the method signature could look something like this:
public static IEnumerable<Range<T>> Collapse<T>(
this IEnumerable<Range<T>>,
IComparable<T> comparer)
{
...
}
我在这里查看了其他一些类似的问题,但我还没有找到它的实现.这个答案 和同一问题的其他一些答案描述了算法,但我不太确定我是否理解这些算法.也不是特别擅长实现算法,所以我希望这里有人可以帮助我.
I have looked at some other questions here that are kind of similar, but I haven't found an implementation of this yet. This answer and some other answers to the same question describes algorithms, but I am not quite sure if I understand the algorithms. Not especially good at implementing algorithms either, so I was hoping someone here could help me out.
推荐答案
这似乎可行且易于理解.
This seems to works and is easy to understand.
public static IEnumerable<Range<T>> Collapse<T>(this IEnumerable<Range<T>> me, IComparer<T> comparer)
{
List<Range<T>> orderdList = me.OrderBy(r => r.Start).ToList();
List<Range<T>> newList = new List<Range<T>>();
T max = orderdList[0].End;
T min = orderdList[0].Start;
foreach (var item in orderdList.Skip(1))
{
if (comparer.Compare(item.End, max) > 0 && comparer.Compare(item.Start, max) > 0)
{
newList.Add(new Range<T> { Start = min, End = max });
min = item.Start;
}
max = comparer.Compare(max, item.End) > 0 ? max : item.End;
}
newList.Add(new Range<T>{Start=min,End=max});
return newList;
}
<小时>
这是我在评论中提到的变化.这基本上是一样的,但需要对结果进行一些检查和生成,而不是在返回之前收集到一个列表中.
Here is the variation which I mentioned in the comments. It's basically the same thing, but with some checking and yielding of the results instead of collecting in a list before returning.
public static IEnumerable<Range<T>> Collapse<T>(this IEnumerable<Range<T>> ranges, IComparer<T> comparer)
{
if(ranges == null || !ranges.Any())
yield break;
if (comparer == null)
comparer = Comparer<T>.Default;
var orderdList = ranges.OrderBy(r => r.Start);
var firstRange = orderdList.First();
T min = firstRange.Start;
T max = firstRange.End;
foreach (var current in orderdList.Skip(1))
{
if (comparer.Compare(current.End, max) > 0 && comparer.Compare(current.Start, max) > 0)
{
yield return Create(min, max);
min = current.Start;
}
max = comparer.Compare(max, current.End) > 0 ? max : current.End;
}
yield return Create(min, max);
}
这篇关于用于折叠一组可能重叠的范围的好的通用算法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:用于折叠一组可能重叠的范围的好的通用算法是什么?
- WebMatrix WebSecurity PasswordSalt 2022-01-01
- MoreLinq maxBy vs LINQ max + where 2022-01-01
- 如何用自己压缩一个 IEnumerable 2022-01-01
- Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01
- 输入按键事件处理程序 2022-01-01
- 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01
- 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01
- C# 中多线程网络服务器的模式 2022-01-01
- 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01
- C#MongoDB使用Builders查找派生对象 2022-09-04