我做了一个扩展方法来查找集合中连续值的数量。因为它是通用的,所以我允许调用者定义“增量”,它是一个Func<>应该增加值以检查是否存在“下一个”值。
但是,如果调用者传递了一个不正确的递增器(即x => x),它将导致无限递归循环。有关干净的方法的任何建议,以防止这种情况?
public static int CountConsecutive<T>(this IEnumerable<T> values, T startValue, Func<T, T> incrementor)
{
if (values == null)
{
throw new ArgumentNullException("values");
}
if (incrementor == null)
{
throw new ArgumentNullException("incrementor");
}
var nextValue = incrementor(startValue);
return values.Contains(nextValue)
? values.CountConsecutive(nextValue, incrementor) + 1
: 1;
}
答案 0 :(得分:4)
要处理最简单的情况,您可以这样做:
var nextValue = incrementor(startValue);
if (nextValue.Equals(startValue)) {
throw new ArgumentException("incrementor");
}
一般情况下,请执行以下操作:
public static int CountConsecutive<T>(this IEnumerable<T> values, T startValue, Func<T, T> incrementor) {
if (values == null) {
throw new ArgumentNullException("values");
}
if (incrementor == null) {
throw new ArgumentNullException("incrementor");
}
ISet<T> seen = new HashSet<T>();
return CountConsecutive(values, startValue, incrementor, seen);
}
private static int CountConsecutive<T>(IEnumerable<T> values, T startValue, Func<T, T> incrementor, ISet<T> seen) {
if (!seen.Add(startValue)) {
throw new ArgumentException("incrementor");
}
var nextValue = incrementor(startValue);
return values.Contains(nextValue)
? values.CountConsecutive(nextValue, incrementor) + 1
: 1;
}
答案 1 :(得分:1)
您可以将nextValue与startValue进行比较(您需要T来实现IComparable)。
这将解决这个错误,它不会解决一个令人讨厌的增量错误,它返回一个循环 - a1,a2,a3,...,an,a1。我认为您不想处理此案例,但
答案 2 :(得分:0)
从最纯粹的意义上说,这是Halting Problem的尝试而且是不可判定的。对于除了最简单的情况之外的所有情况,您都必须相信那些调用您方法的人。
与其他人一样,您可以对等式进行简单检查,以显示下一个值是不同的。存储每个访问过的T
都可以,但您最终必须担心内存 。
顺便说一下,这是一个容易实现的StackOverflowException,所以你必须警惕任何连续值都有很多的数据集。
var x = Enumerable.Range(1, 100000).CountConsecutive(1, x => x+1);