C# 什么';这是一个很好的通用算法,用于折叠一组可能重叠的范围?
我有一个方法可以获取这个类的许多对象C# 什么';这是一个很好的通用算法,用于折叠一组可能重叠的范围?,c#,algorithm,generics,range,union,C#,Algorithm,Generics,Range,Union,我有一个方法可以获取这个类的许多对象 class Range<T> { public T Start; public T End; } 我已经研究了其他一些类似的问题,但是我还没有找到实现这个的方法。同一个问题的其他一些答案描述了算法,但我不确定我是否理解算法。也不是特别擅长实现算法,所以我希望这里的人能帮我 这可能会被优化 using System.Collections.Generic; using System.Linq; using System; stat
class Range<T>
{
public T Start;
public T End;
}
我已经研究了其他一些类似的问题,但是我还没有找到实现这个的方法。同一个问题的其他一些答案描述了算法,但我不确定我是否理解算法。也不是特别擅长实现算法,所以我希望这里的人能帮我 这可能会被优化
using System.Collections.Generic;
using System.Linq;
using System;
static class Range
{
public static Range<T> Create<T>(T start, T end)
{
return new Range<T>(start, end);
}
public static IEnumerable<Range<T>> Normalize<T>(
this IEnumerable<Range<T>> ranges)
{
return Normalize<T>(ranges, null);
}
public static IEnumerable<Range<T>> Normalize<T>(
this IEnumerable<Range<T>> ranges, IComparer<T> comparer)
{
var list = ranges.ToList();
if (comparer == null) comparer = Comparer<T>.Default;
for (int i = list.Count - 1; i >= 0; i--)
{
var item = list[i];
for (int j = 0; j < i; j++)
{
Range<T>? newValue = TryMerge<T>(comparer, item, list[j]);
// did we find a useful transformation?
if (newValue != null)
{
list[j] = newValue.GetValueOrDefault();
list.RemoveAt(i);
break;
}
}
}
list.Sort((x, y) =>
{
int t = comparer.Compare(x.Start, y.Start);
if (t == 0) t = comparer.Compare(x.End, y.End);
return t;
});
return list.AsEnumerable();
}
private static Range<T>? TryMerge<T>(IComparer<T> comparer, Range<T> item, Range<T> other)
{
if (comparer.Compare(other.End, item.Start) == 0)
{ // adjacent ranges
return new Range<T>(other.Start, item.End);
}
if (comparer.Compare(item.End, other.Start) == 0)
{ // adjacent ranges
return new Range<T>(item.Start, other.End);
}
if (comparer.Compare(item.Start, other.Start) <= 0
&& comparer.Compare(item.End, other.End) >= 0)
{ // item fully swalls other
return item;
}
if (comparer.Compare(other.Start, item.Start) <= 0
&& comparer.Compare(other.End, item.End) >= 0)
{ // other fully swallows item
return other;
}
if (comparer.Compare(item.Start, other.Start) <= 0
&& comparer.Compare(item.End, other.Start) >= 0
&& comparer.Compare(item.End, other.End) <= 0)
{ // partial overlap
return new Range<T>(item.Start, other.End);
}
if (comparer.Compare(other.Start, item.Start) <= 0
&& comparer.Compare(other.End, item.Start) >= 0
&& comparer.Compare(other.End, item.End) <= 0)
{ // partial overlap
return new Range<T>(other.Start, item.End);
}
return null;
}
}
public struct Range<T>
{
private readonly T start, end;
public T Start { get { return start; } }
public T End { get { return end; } }
public Range(T start, T end)
{
this.start = start;
this.end = end;
}
public override string ToString()
{
return start + " to " + end;
}
}
static class Program
{
static void Main()
{
var data = new[]
{
Range.Create(1,5), Range.Create(3,9),
Range.Create(11,15), Range.Create(12,14),
Range.Create(13,20)
};
var result = data.Normalize();
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
使用System.Collections.Generic;
使用System.Linq;
使用制度;
静态类范围
{
公共静态范围创建(T开始,T结束)
{
返回新范围(开始、结束);
}
公共静态IEnumerable规范化(
这是(可数范围)
{
返回标准化(范围,空);
}
公共静态IEnumerable规范化(
这是(数字范围,IComparer(比较器)
{
var list=ranges.ToList();
如果(comparer==null)comparer=comparer.Default;
对于(int i=list.Count-1;i>=0;i--)
{
var项目=列表[i];
对于(int j=0;j
{
int t=比较器比较(x.Start,y.Start);
如果(t==0)t=comparer.Compare(x.End,y.End);
返回t;
});
返回列表;
}
专用静态范围?TryMerge(IComparer比较器、范围项目、范围其他)
{
if(comparer.Compare(other.End,item.Start)==0)
{//相邻范围
返回新范围(other.Start、item.End);
}
if(comparer.Compare(item.End,other.Start)==0)
{//相邻范围
返回新范围(item.Start,other.End);
}
if(comparer.Compare(item.Start,other.Start)=0)
{//item完全替换其他
退货项目;
}
if(comparer.Compare(other.Start,item.Start)=0)
{//其他完全吞咽项目
归还他人;
}
if(comparer.Compare(item.Start,other.Start)=0
&&comparer.Compare(item.End,other.End)staticvoidmain(string[]args){
列表范围=新列表()
{
新范围(3,9),
新范围(1,5),
新范围(11,15),
新范围(12,14),
新范围(13,20),
};
var orderedRanges=ranges.OrderBy(r=>r.Start);
var lastRange=新范围(orderedRanges.First().Start,orderedRanges.First().End);
List newranges=新列表();
添加(最后一个范围);
foreach(orderedRanges.Skip(1)中的变量范围){
如果(range.Start>=lastRange.Start&&range.Start lastRange.End){
lastRange.End=范围.End;
}
else if(range.Start>lastRange.End){
lastRange=新范围(Range.Start,Range.End);
添加(最后一个范围);
}
}
foreach(新范围内的风险值r){
Console.WriteLine(“{0},{1}”,r.Start,r.End);
}
}
类似于此。没有验证它是否可以与所有输入一起工作。一个针对非详细用户的Python解决方案:
ranges = [
(11, 15),
(3, 9),
(12, 14),
(13, 20),
(1, 5)]
result = []
cur = None
for start, stop in sorted(ranges): # sorts by start
if cur is None:
cur = (start, stop)
continue
cStart, cStop = cur
if start <= cStop:
cur = (cStart, max(stop, cStop))
else:
result.append(cur)
cur = (start, stop)
result.append(cur)
print result
范围=[
(11, 15),
(3, 9),
(12, 14),
(13, 20),
(1, 5)]
结果=[]
cur=无
对于开始,在排序(范围)中停止:#按开始排序
如果cur为None:
cur=(开始、停止)
持续
cStart,cStop=cur
如果开始折叠列表的想法对我来说只是尖叫着“减少”,但它并没有像我希望的那样优雅
def collapse(output,next_range):
last_start,last_end = output[-1]
next_start, next_end = next_range
if (next_start <= last_end):
output[-1] = (last_start, max(next_end, last_end))
else:
output.append(next_range)
return output
ranges = [
(11, 15),
(3, 9),
(12, 14),
(13, 20),
(1, 5)]
ranges.sort()
result = [ranges.pop(0)]
reduce(collapse, ranges,result)
print result
def折叠(输出,下一个_范围):
最后开始,最后结束=输出[-1]
下一个开始,下一个结束=下一个范围
if(next_start这里是一个简单的循环推进,但至少是清楚的
- 在我的简单测试中,它适用于DateTime和Int
- 大多数复杂性存在于范围上的重叠/组合方法中
- 该算法实际上很容易理解,没有浮动变量
- 向Range类添加一些功能,这在一般情况下可能很有用
--这一行故意毫无意义,以解决降价问题--
公共静态类拼贴
{
公共静态IEnumerable崩溃(此IEnumerable me)
其中T:struct
{
var result=新列表();
var sorted=me.OrderBy(x=>x.Start.ToList();
做{
var first=sorted.FirstOrDefault();
排序。移除(第一);
while(sorted.Any(x=>x.Overlap(first))){
var other=sorted.FirstOrDefault(x=>x.Overlap(first));
第一个=第一个。合并(其他);
已排序。移除(其他);
}
结果。添加(第一);
}而(sorted.Count>0);
返回结果;
}
}
[调试器显示(“范围{Start}-{End}”)]
公共类范围,其中T:struct
{
公共T开始{set;get;}
公共T端{set;get;}
公共布尔重叠(范围其他)
{
返回(在(其他.开始)| |在(其他.结束)| |其他.在(这个.开始)| |其他.在(这个.结束))内);
}
公共边界内(T点)
{
var Comp=比较器默认值;
var st=复合比较(点,此起点);
var ed=比较(本点、终点);
返回(st>=0&&ed>=0);
}
///合并到范围,更新当前范围
公共无效合并(范围其他)
{
var Comp=比较器默认值;
如果(Comp.Compare(this.Start,other.Start)>0)this.Start=other.Start;
如果(Comp.Compare(other.End,this.End)>0)this.End=other.End;
}
///合并到ra
ranges = [
(11, 15),
(3, 9),
(12, 14),
(13, 20),
(1, 5)]
result = []
cur = None
for start, stop in sorted(ranges): # sorts by start
if cur is None:
cur = (start, stop)
continue
cStart, cStop = cur
if start <= cStop:
cur = (cStart, max(stop, cStop))
else:
result.append(cur)
cur = (start, stop)
result.append(cur)
print result
def collapse(output,next_range):
last_start,last_end = output[-1]
next_start, next_end = next_range
if (next_start <= last_end):
output[-1] = (last_start, max(next_end, last_end))
else:
output.append(next_range)
return output
ranges = [
(11, 15),
(3, 9),
(12, 14),
(13, 20),
(1, 5)]
ranges.sort()
result = [ranges.pop(0)]
reduce(collapse, ranges,result)
print result
public static class CollapseRange
{
public static IEnumerable<Range<T>> Collapse<T>(this IEnumerable<Range<T>> me)
where T:struct
{
var result = new List<Range<T>>();
var sorted = me.OrderBy(x => x.Start).ToList();
do {
var first = sorted.FirstOrDefault();
sorted.Remove(first);
while (sorted.Any(x => x.Overlap(first))) {
var other = sorted.FirstOrDefault(x => x.Overlap(first));
first = first.Combine(other);
sorted.Remove(other);
}
result.Add(first);
} while (sorted.Count > 0);
return result;
}
}
[DebuggerDisplay("Range {Start} - {End}")]
public class Range<T> where T : struct
{
public T Start { set; get; }
public T End { set; get; }
public bool Overlap(Range<T> other)
{
return (Within(other.Start) || Within(other.End) || other.Within(this.Start) || other.Within(this.End));
}
public bool Within(T point)
{
var Comp = Comparer<T>.Default;
var st = Comp.Compare(point, this.Start);
var ed = Comp.Compare(this.End, point);
return (st >= 0 && ed >= 0);
}
/// <summary>Combines to ranges, updating the current range</summary>
public void Merge(Range<T> other)
{
var Comp = Comparer<T>.Default;
if (Comp.Compare(this.Start, other.Start) > 0) this.Start = other.Start;
if (Comp.Compare(other.End, this.End) > 0) this.End = other.End;
}
/// <summary>Combines to ranges, returning a new range in their place</summary>
public Range<T> Combine(Range<T> other)
{
var Comp = Comparer<T>.Default;
var newRange = new Range<T>() { Start = this.Start, End = this.End };
newRange.Start = (Comp.Compare(this.Start, other.Start) > 0) ? other.Start : this.Start;
newRange.End = (Comp.Compare(other.End, this.End) > 0) ? other.End : this.End;
return newRange;
}
}
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;
}
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);
}
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import edu.emory.mathcs.backport.java.util.Collections;
import junit.framework.TestCase;
public class Range2Test extends TestCase {
public void testCollapse() throws Exception {
Set<Range<Integer>> set = new HashSet<Range<Integer>>();
set.add(new Range<Integer>(1, 5));
set.add(new Range<Integer>(3, 9));
set.add(new Range<Integer>(11, 15));
set.add(new Range<Integer>(12, 14));
set.add(new Range<Integer>(13, 20));
Set<Range<Integer>> expected = new HashSet<Range<Integer>>();
expected.add(new Range<Integer>(1, 9));
expected.add(new Range<Integer>(11, 20));
assertEquals(expected, collapse(set));
}
private static <T extends Comparable<T>> Set<Range<T>> collapse(Set<Range<T>> ranges) {
if (ranges == null)
return null;
if (ranges.size() < 2)
return new HashSet<Range<T>>(ranges);
ArrayList<Range<T>> list = new ArrayList<Range<T>>(ranges);
Collections.sort(list);
Set<Range<T>> result = new HashSet<Range<T>>();
Range<T> r = list.get(0);
for (Range<T> range : list)
if (r.overlaps(range)) {
r = r.union(range);
} else {
result.add(r);
r = range;
}
result.add(r);
return result;
}
private static class Range<T extends Comparable<T>> implements Comparable<Range<T>> {
public Range(T start, T end) {
if (start == null || end == null)
throw new NullPointerException("Range requires start and end.");
this.start = start;
this.end = end;
}
public T start;
public T end;
private boolean contains(T t) {
return start.compareTo(t) <= 0 && t.compareTo(end) <= 0;
}
public boolean overlaps(Range<T> that) {
return this.contains(that.start) || that.contains(this.start);
}
public Range<T> union(Range<T> that) {
T start = this.start.compareTo(that.start) < 0 ? this.start : that.start;
T end = this.end.compareTo(that.end) > 0 ? this.end : that.end;
return new Range<T>(start, end);
}
public String toString() {
return String.format("%s - %s", start, end);
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + end.hashCode();
result = prime * result + start.hashCode();
return result;
}
@SuppressWarnings("unchecked")
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Range<T> that = (Range<T>) obj;
return end.equals(that.end) && start.equals(that.start);
}
public int compareTo(Range<T> that) {
int result = this.start.compareTo(that.start);
if (result != 0)
return result;
return this.end.compareTo(that.end);
}
}
}
def merge a , b
return b if a.nil?
if b.begin <= a.end
(a.begin..b.end)
el
[a , b ] #no overlap
end
end
ranges = [(1..5),(11..15),(3..9),(12..14),(13..20)]
sorted_ranges = ranges.sort_by {|r| r.begin} #sorted by the start of the range
merged_ranges = sorted_ranges.inject([]) do |m , r|
last = m.pop
m << merge(last , r)
m.flatten
end
puts merged_ranges
package main
import "sort"
import "fmt"
type TupleList [][]int
// Methods required by sort.Interface.
func (s TupleList) Len() int {
return len(s)
}
func (s TupleList) Less(i, j int) bool {
return s[i][1] < s[j][1]
}
func (s TupleList) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func main() {
ranges :=
TupleList{
{11, 15},
{3, 9},
{12, 14},
{13, 20},
{1, 5}}
fmt.Print(ranges)
sort.Sort(ranges)
fmt.Print("\n")
fmt.Print(ranges)
fmt.Print("\n")
result := TupleList{}
var cur []int
for _, t := range ranges {
if cur == nil {
cur = t
continue
}
cStart, cStop := cur[0], cur[1]
if t[0] <= cStop {
cur = []int{cStart, max(t[1], cStop)}
} else {
result = append(result, cur)
cur = t
}
}
result = append(result, cur)
fmt.Print(result)
}
func max(v1, v2 int) int {
if v1 <= v2 {
return v2
}
return v1
}
private static List<Tuple<int, int>> Insert(List<Tuple<int, int>> ranges, int startIndex, int endIndex)
{
if (ranges == null || ranges.Count == 0)
return new List<Tuple<int, int>> { new Tuple<int, int>(startIndex, endIndex) };
var newIndex = ranges.Count;
for (var i = 0; i < ranges.Count; i++)
{
if (ranges[i].Item1 > startIndex)
{
newIndex = i;
break;
}
}
var min = ranges[0].Item1;
var max = ranges[0].Item2;
var newRanges = new List<Tuple<int, int>>();
for (var i = 0; i <= ranges.Count; i++)
{
int rangeStart;
int rangeEnd;
if (i == newIndex)
{
rangeStart = startIndex;
rangeEnd = endIndex;
}
else
{
var range = ranges[i > newIndex ? i - 1 : i];
rangeStart = range.Item1;
rangeEnd = range.Item2;
}
if (rangeStart > max && rangeEnd > max)
{
newRanges.Add(new Tuple<int, int>(min, max));
min = rangeStart;
}
max = rangeEnd > max ? rangeEnd : max;
}
newRanges.Add(new Tuple<int, int>(min, max));
return newRanges;
}