在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
运算符,以便在更复杂的场景中使用时易于编写一些易于阅读的代码。
例如,我需要执行此操作(当然不会编译):
<
与上面介绍的可行方法相比,这将导致更容易阅读的代码。
有没有简单的方法可以实现,我需要自己实现吗?
答案 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