我有许多对象,每个对象都有3个数字属性:“高”,“低”和“决胜局”。它们将按如下方式排序:如果对象的低值高于另一个对象的高值,则它在列表中显示在它之前。同样,如果一个对象的高位低于另一个低位,它会出现在列表的后面。但是在两个对象具有冲突范围的情况下(例如,一个高在另一个对象的低和高之间),会考虑仲裁器属性,其中具有较高仲裁器值的对象会在列表的前面放置。
我特意使用c#,但我认为这里的想法与语言无关,因此任何类型的代码(没有双关语)都是受欢迎的。
另外,我已经自己做了这件事。我有一个嵌套的for循环,到目前为止对我来说还没有用。我会放弃一些代码,但我在手机上,这使它成为一件苦差事。此外,这对你来说可能很有趣,无论如何你都不需要我的丑陋代码。
答案 0 :(得分:3)
你是否假设Min <= Tie <= Max
?您在问题中没有这样说,如果不这样做,排序顺序没有明确定义,因为它不是transitive。例如,将范围写为[Min, Tie, Max]
,请考虑:
A: [5,-10, 6]
B: [0, 1, 10]
C: [2, 3, 4]
A&lt; B(因为它们重叠并且-10 <1)
B&lt; C(因为它们重叠并且1 <3)
但是A&gt; C(因为它们不重叠且5> 4)
如果是,您可以为Range
课程定义自定义IComparer<Range>
,并将其传递给任何c#sort method。
更新,这是一个这样的实现。
public struct RangeWithTie<T> where T : IEquatable<T>, IComparable<T>
{
readonly T min;
readonly T max;
readonly T tie;
readonly bool isNonEmpty;
public static Range<T> Empty = new Range<T>();
public static IComparer<RangeWithTie<T>> CreateSortingComparer()
{
return new RangeWithTieComparer();
}
public RangeWithTie(T start, T tie, T end)
{
// Enfore start <= tie <= end
var comparer = Comparer<T>.Default;
if (comparer.Compare(start, end) > 0) // if start > end
{
throw new ArgumentOutOfRangeException("start and end are reversed");
}
else if (comparer.Compare(start, tie) > 0)
{
throw new ArgumentOutOfRangeException("tie is less than start");
}
else if (comparer.Compare(tie, end) > 0)
{
throw new ArgumentOutOfRangeException("tie is bigger than end");
}
else
{
this.min = start;
this.max = end;
this.tie = tie;
}
this.isNonEmpty = true;
}
public T Min { get { return min; } }
public T Max { get { return max; } }
public T Tie { get { return tie; } }
public bool IsEmpty { get { return !isNonEmpty; } }
public class RangeWithTieComparer : IComparer<RangeWithTie<T>>
{
#region IComparer<RangeWithTie<T>> Members
public int Compare(RangeWithTie<T> x, RangeWithTie<T> y)
{
// return x - y.
if (x.IsEmpty)
{
if (y.IsEmpty)
return 0;
else
return -1;
}
else if (y.IsEmpty)
{
return 1;
}
var comparer = Comparer<T>.Default;
if (comparer.Compare(y.Min, x.Max) > 0)
return -1;
else if (comparer.Compare(x.Min, y.Max) > 0)
return 1;
return comparer.Compare(x.Tie, y.Tie);
}
#endregion
}
public override string ToString()
{
if (IsEmpty)
return "Empty";
StringBuilder s = new StringBuilder();
s.Append('[');
if (Min != null)
{
s.Append(Min.ToString());
}
s.Append(", ");
if (Tie != null)
{
s.Append(Tie.ToString());
}
s.Append(", ");
if (Max != null)
{
s.Append(Max.ToString());
}
s.Append(']');
return s.ToString();
}
}
这可以这样使用:
var sortedRanges = ranges.OrderBy(x => x, RangeWithTie<double>.CreateSortingComparer()).ToArray();
我没有直接生成结构实现IComparer<RangeWithTie<T>>
,因为具有相同比较的范围不一定相等。例如,[-1,0,1]
和[-2,0,1]
具有相同的比较但不相等。
答案 1 :(得分:1)
快速解决方案和用于测试它的控制台应用程序。此方法将返回两个对象中较大的一个。只需将dynamic
替换为您需要的适当对象类型。
class Program
{
private static object Sort(dynamic first, dynamic second)
{
if (OverlapExists(first, second))
{
// Note: If tiebreakers are equal, the first will be returned:
return first.tiebreaker >= second.tiebreaker ? first : second;
}
else
{
// Note: Only need to test one value (just high); Since we know
// there is no overlap, the whole object (both high and low) must
// be either over or under that which it is compared to:
return first.high > second.high ? first : second;
}
}
private static bool OverlapExists(dynamic first, dynamic second)
{
return (first.low < second.high) && (second.low < first.high);
}
static void Main(string[] args)
{
dynamic first = new {name="first", high = 10,
tiebreaker = 5, low = 1 };
dynamic second = new {name="second", high = 15,
tiebreaker = 12, low = 11 };
dynamic third = new {name="third", high = 20,
tiebreaker = 9, low = 6 };
var firstResult = Sort(first, second);
var secondResult = Sort(first, third);
var thirdResult = Sort(second, third);
Console.WriteLine("1) " + first.ToString()
+ "\nVS: " + second.ToString());
Console.WriteLine("Winner: " + firstResult.name);
Console.WriteLine("\n2) " + first.ToString()
+ "\nVS: " + third.ToString());
Console.WriteLine("Winner: " + secondResult.name);
Console.WriteLine("\n3) " + second.ToString()
+ "\nVS: " + third.ToString());
Console.WriteLine("Winner: " + thirdResult.name);
Console.ReadKey();
}
}
答案 2 :(得分:0)
假设您有一个List<T>
(T为您的objects
,具有高,低和领带属性),那么您可以使用
list.Sort(…);
以Comparison<T>
作为参数。这是一个委托你需要2个对象,并且应该返回&lt; 0,当你的对象的第一个实例应该是另一个实例的头部时,如果它们具有相同的顺序,则为0;如果第二个第二个对象应该在第一个实例之前,则为> 0;
或者您可以传递一个自定义比较器(实现IComparer<T>
),它与Comparison<T>
基本相同但是通知接口。
答案 3 :(得分:0)
无论您的逻辑是什么,您都可以实现IComparable以启用Array或List的排序功能。因此,如下面的代码所示,
public class MyStuff : IComparable<MyStuff>
{
public int High { get; set; }
public int Low { get; set; }
public int TieBreaker { get; set; }
public int CompareTo(MyStuff other)
{
// if an object's low is higher than another object's high,
// it appears before it in the list
if ((this.Low > other.High) ||
// if its high is between the other object's low and
// high then compare their tiebreaker
(this.High > other.Low && this.High < other.High &&
this.TieBreaker > other.TieBreaker))
return 1;
else if (this.Low == other.High)
return 0;
else
return -1;
}
}
基本思路是CompareTo返回1(在其他之前移动),0(保留两个位置)或-1(在其他位置之后移动),具体取决于您的排序逻辑。
答案 4 :(得分:-1)
class DataObject : IComparable<DataObject>
{
public double High, Low, Tiebreaker;
public int CompareTo(DataObject obj)
{
// this doesn't seem to make sense as a range sort, but seems to match your question...
// low > another high
if (this.Low != obj.High)
return this.Low.CompareTo(obj.High);
// otherwise sort tiebreaker ascending
else this.TieBreaker.CompareTo(obj.TieBreaker);
}
}
用作
var items = new[] { new DataObject(1,2,3), new DataObject(4,5,6) };
Array.Sort<DataObject>(items);
// items is now sorted