有没有一种简单的方法可以在C#中堆叠比较运算符?

时间:2019-05-07 15:07:00

标签: c# comparison

在c#中,可以轻松地比较任何实现比较运算符的类型,例如@Echo Off SetLocal DisableDelayedExpansion Set "DWM=%__AppDir__%wbem" Rem Fixes 'Invalid XSL format (or) file name' errors in some Windows versions. Set "CSV=" For /F "Delims=" %%A In ('"Dir /B/S/A-D "%DWM%\csv.xsl" 2>Nul"' )Do If Not Defined CSV Set "CSV=%%A" If Not Defined CSV Exit /B Set "Serial#=Null" For /F "Skip=2Tokens=1*Delims=," %%A In ( '""%DWM%\wmic.exe" BIOS Get SerialNumber /Format:"%CSV%" 2>Nul"' )Do For /F Tokens^=* %%C In ("%%~B")Do Set "Serial#=%%~C" Set "Model#=Null" For /F "Skip=2Tokens=1*Delims=," %%A In ( '""%DWM%\wmic.exe" CSProduct Get Version /Format:"%CSV%" 2>Nul"' )Do For /F Tokens^=* %%C In ("%%~B")Do Set "Model#=%%~C" Echo "%Model#%"-"%Serial#%">>"test.txt" Pause <。例如,我可以这样做:

>

但是,我无法执行以下操作

var date1 = new DateTime(1000);
var date2 = new DateTime(2000);
var date3 = new DateTime(3000);
var result = date1 < date2; // true
  

这不会编译,因为第一次比较返回的是布尔值,无法与其他日期进一步比较

因此,我必须这样做,(如果第一个var result = date1 < date2 < date3; // error 较早,DateTime.CompareTo(DateTime)返回-1:

DateTime

或者只是这样做:

var result = date1.CompareTo(date2) + date2.CompareTo(date3) == -2; // true

但是,我想知道是否有可能多次链接var result = date1 < date2 && date2 < date3; // true 运算符,以便在更复杂的场景中使用时易于编写一些易于阅读的代码。

例如,我需要执行此操作(当然不会编译):

<

与上面介绍的可行方法相比,这将导致更容易阅读的代码。

有没有简单的方法可以实现,我需要自己实现吗?

2 个答案:

答案 0 :(得分:4)

这就是我要做的:

public static class Extensions
{
    public static bool InOrderAscending<T>(this IEnumerable<T> values) 
        where T : struct, IComparable 
    =>
        !values.Zip(values.Skip(1), (value, nextValue) => value.CompareTo(nextValue))
             .Any(x => x >= 0);

    public static bool InOrderAscending<T>(params T[] values) where T : struct, IComparable 
        => values.InOrderAscending();
}

这是它的工作方式:Zip()接受两个IEnumerables并枚举其中的项目 将它们配对:

var a = new[] { 1, 2, 3 };
var b = new[] { 4, 5, 6, 7 };

var zipped = a.Zip(b, (aitem, bitem) => $"{aitem},{bitem}").ToList();

压缩后将包含{ "1, 4", "2, 5", "3, 6" }

请注意,7未使用:没有匹配项,因此将其丢弃。这符合LINQ的哲学,即无需进行范围检查。

接下来,Skip(1)跳过一项并枚举其余项。

因此,我正在压缩两个序列:原始序列,以及原始序列的第二个到最后一个项目。

{a, b, c}
{b, c}

因此,这将为我们提供(a,b)和(b,c)的序列。

与将arg[i]arg[i+1]进行比较相比,它的可读性较差,但是可以避免处理索引。

因此,我们的zip表达式返回了一系列比较结果。对于每对相邻的项目,我们调用CompareTo()并返回结果。

public static bool InOrderDescending<T>(params T[] values) where T : struct, IComparable
{
    List<int> comparisons = 
        values.Zip(values.Skip(1), (value, nextValue) => value.CompareTo(nextValue))
              .ToList();

    //  Now we finish by checking that sequence of integers for any positive values, 
    //  where a positive value means that `value` was greater than `nextValue`
    var haveOutOfOrderItems = comparisons.Any(x => x >= 0);

    //  If none of the values were positive, we're in order. 
    return !haveOutOfOrderItems;
}

我只为值类型编写了此方法,因此我不必担心null。 null大于还是小于new Button()this.SettingsPage?这取决于调用者,因此我将编写一个引用类型的重载,该重载采用类型为IComparer<T>的参数,或者只是一个lambda(编辑:也许我们应该写一个扩展方法来实现自偏移量- zip,但从lambda返回一个任意返回类型的序列;我们将使用它来编写此代码)。

public static bool InOrderAscending<T>(this IEnumerable<T> values, Func<T, T, int> compare) 
    where T : class 
=>
    !values.Zip(values.Skip(1), (value, nextValue) => compare(value, nextValue))
        .Any(x => x >= 0);

答案 1 :(得分:2)

按照@Ed Plunkett和@juharr的建议,我实现了InOrder()

public static bool InOrder<T>(this IEnumerable<T> collection) where T : struct, IComparable
{
    var array = collection.ToArray();
    if (array.Length < 2)
        return true;
    var comp = 0;
    for (int i = 0; i < array.Length - 1; i++)
    {
        comp += array[i].CompareTo(array[i + 1]);
    }

    return comp == 1 - array.Length;
}

public static bool InOrder<T>(params T[] args) where T: struct, IComparable
{
    return args.InOrder();
}

它产生以下输出

var date1 = new DateTime(1000);
var date2 = new DateTime(2000);
var date3 = new DateTime(3000);
var result = InOrder(date1, date2); // true
var result1 = InOrder(date2, date1); // false
var result2 = InOrder(date1, date2, date3); // true
var result3 = InOrder(date1, date3, date2); // false