作为collapses overlapping ranges方法的后续跟踪,我认为我会尝试创建一个组合相邻范围的方法。
基本上,在运行Collapse方法之后,你可能会得到例如1到5和6到10.我想将它们组合成一个范围,1到10。
这是我到目前为止所提出的,但它并没有真正起作用。有没有人发现我的问题或有更好的替代解决方案?
public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent)
{
using (var sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
yield break;
var first = sourceIterator.Current;
while (sourceIterator.MoveNext())
{
var second = sourceIterator.Current;
if (isAdjacent(first.End, second.Start))
{
yield return Range.Create(first.Start, second.End);
}
else
yield return first;
first = second;
}
yield return first;
}
}
答案 0 :(得分:1)
它只会合并两个相邻的范围,而不是三个或更多。保留最后一个,直到找到间隙或列表的末尾。
public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent)
{
Range<T> current = null;
foreach (Range<T> item in source)
{
if (current == null)
{
current = item;
}
else
{
if (isAdjacent(current.End, item.Start))
{
current = Range.Create(current.Start, item.End);
}
else
{
yield return current;
current = item;
}
}
}
if (current != null)
yield return current;
}
答案 1 :(得分:1)
我已经达成了这个解决方案。一个先决条件是范围按升序/降序排序,具体取决于Func。它将合并相邻的范围,它仍然是延迟执行。我没有进行很多测试,因此可能存在破坏这种情况的边缘情况。是异教徒: - )
编辑:稍微缩短代码。据我所知,它有效。但是遗漏了null
。
public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent)
{
using (var it = source.GetEnumerator())
{
if (!it.MoveNext())
yield break;
var item = it.Current;
while (it.MoveNext())
if (isAdjacent(item.End, it.Current.Start))
{
item = Range.Create(item.Start, it.Current.End);
}
else
{
yield return item;
item = it.Current;
}
yield return item;
}
}
static void Main(string[] args)
{
var ranges = new List<Range<int>>
{
Range.Create(1,3), Range.Create(4,5), Range.Create(7,10),
Range.Create(11,17), Range.Create(20,32), Range.Create(33,80),
Range.Create(90,100),
};
foreach (var range in ranges.MergeAdjacent((r1, r2) => r1 + 1 == r2))
Console.WriteLine(range);
}
// Result: 1-5, 7-20, 25-80, 90-100