假设c#中有一个int类型的列表:
List<int> numbers = new List<int>() { 1, 2, 7, 20, 3 };
是否有一种方法来检查它是否有交替奇数甚至和其中的数字(如上面的例子:如果一个如果它们是偶数那么下一个必须是奇数,反之亦然)?
我知道在循环中检查它很简单,但我正试图使用LINQ来实现这一点和扩展方法。
让我们分析一下这个问题。交替宇称是什么意思?
index : value : value + index
------------------------------
0 : 1 : 1 - note, all sums are odd
1 : 2 : 3
2 : 7 : 9
....
或
index : value : value + index
------------------------------
0 : 2 : 2 - note, all sums are even
1 : 1 : 2
2 : 6 : 8
....
你可以看到(你可以很容易地证明它)交替奇偶校验意味着index + value
和为allodd
或alleven
。让我们用Linq:
List<int> numbers = new List<int>() { 1, 2, 7, 20, 3, 79 };
bool result = numbers
.DefaultIfEmpty()
.Select((item, index) => Math.Abs((long)item + (long)index))
.Aggregate((s, a) => s % 2 == a % 2 ? s % 2 : -1) >= 0;
实现注意事项:
DefaultIfEmpty()
-空序列全部(全部为零)值交替;然而,Aggregate
没有什么可聚合的,并抛出异常。让我们把空序列变成一个元素序列。(long)
为了防止整数溢出(int.MaxValue + index
可以很好地超出int
范围)Math.Abs
: c#可以返回负余数(例如-1 % 2
);我们不希望对此进行额外的检查,所以让我们使用绝对值 然而,我们可以在最终的
Aggregate
中利用这个效应(-1 % 2 == -1
)。扩展方法的解决方案我希望更容易理解:
public static bool IsAlternating(this IEnumerable<int> source) {
if (null == source)
throw new ArgumentNullException(nameof(source));
bool expectedZero = false;
bool first = true;
foreach (int item in source) {
int actual = item % 2;
if (first) {
first = false;
expectedZero = actual == 0;
}
else if (actual == 0 && !expectedZero || actual != 0 && expectedZero)
return false;
expectedZero = !expectedZero;
}
return true;
}
注意,循环解决方案(扩展方法)更有效:当模式不满足时,它立即返回false
。
您可以这样使用LINQ。您可以检查在加号位置是否有最后一个偶数项,或者在偶数位置是否有最后一个奇数项。
List<int> numbers = new List<int>() { 1, 2, 7, 20, 3 };
var temp = numbers.Where((x, i) => (i % 2 == 0 && x % 2 == 0) || (i % 2 == 1 && x % 2 == 1)).Take(1);
int count = temp.Count();
if(count == 0)
{
//true
}
else
{
//false
}
注意:假设你期望在偶数位得到偶数,在奇数位得到奇数。
您可以使用Aggregate
来确定序列是否交替。
假设有0或1个元素,则结果为真。你可以随意修改这个逻辑。
在此基础上可以创建一个扩展方法:public static bool IsAlternatingParitySequenceVerbose(this IEnumerable<int> col)
{
// state:
// -1 - sequence is not alternating
// 0 - even
// 1 - odd
if (!col.Any())
return true;
//check if first value is even
var firstState = Math.Abs(col.First() % 2);
var IsAlternating = col.Skip(1).Aggregate(firstState, (state, val) =>
{
if (state == -1)
return -1;
var current = Math.Abs(val % 2);
if (current == state)
return -1;
return current;
});
return IsAlternating != -1;
}
然后写一行字:
public static bool IsAlternatingParitySequence(this IEnumerable<int> col) =>
!col.Any()
|| col.Skip(1).Aggregate(Math.Abs(col.First() % 2), (state, val) =>
state == -1
? -1
: Math.Abs(val % 2) is var current && current == state
? -1
: current
) != -1;