下面是一个相对简单的扩展方法,它的来源序列,并告诉任何两个元素是否被视为相等的功能,并返回元素的一个序列:
public static IEnumerable<T> Consecutives<T>(this IEnumerable<T> source,
Func<T, T, bool> equals)
{
T last = default(T);
bool first = true;
bool returnedLast = false;
foreach (T current in source)
{
if (!first && equals(current, last))
{
if (!returnedLast)
yield return last;
returnedLast = true;
yield return current;
}
else
returnedLast = false;
first = false;
last = current;
}
}
如果用
尝试
var sequence = new[] { 3, 4, 7, 8, 9, 2, 4, 6, 0, 1, 1, 17, 2, 3, 2, 20 };
var subsequences = sequence.Consecutives((x, y) => x % 2 == y % 2);
你将得到: 2 4 6 0 1 1 17 2 20
如果你的序列不具有任何重复,T他雷蒙德的解决方案的扩展是效率低下,而且很简单:
public static IEnumerable<T> Consecutives<T>(this IEnumerable<T> source,
Func<T, T, bool> equals)
{
return source.Zip(source.Skip(1), (x, y) => new[] { x, y })
.Where(d => equals(d[0], d[1]))
.SelectMany(d => d)
.Distinct();
}
哇。你的“简单”的定义显然与我的完全不同! – Gabe
不要将长度与非简单混为一谈。这个算法*很简单。从序列中读取,跟踪当前的“投影”(我称它为resultOfCurrentSequence)。对于你遇到的相同投影的每个后续项目,将它添加到当前的子序列(我称它为“currentSequence”)。当遇到不同的东西时,如果长度超过一个,则产生当前的子序列,开始一个新的子序列并用新的投影替换旧的投影。如果到达序列的末尾,并且当前子序列的长度不止一个,则将其退回。 – jason
我不是说你的*算法不简单,只是代码不是(我不是说你的代码有什么问题)。在22行中,它包含了对构造函数,方法和属性的14次调用,加上4个'if's和'while' - 这就忽略了缺少'using'来处理枚举数。而且,返回一系列序列并不像返回一个平坦序列那么简单。我的解决方案缩短了几行,没有构造函数/方法/属性调用,但它仍然不是我认为的“简单”。 – Gabe