我正在使用访问者类型的模式遍历一个集合,并且需要访问列表中的当前项和下一项。目前,我是通过如下的扩展方法来实现的
public void Visit<TItem>(this IEnumerable<TItem> theList, Action<TItem, TItem> visitor)
{
for (i = 0; i <= theList.Count - 1; i++) {
if (i == theList.Count - 1) {
visitor(theList(i), null);
} else {
visitor(theList(i), theList(i + 1));
}
}
}我想知道是否有其他/更好/更优雅的方法来实现这一点?目前,我认为我只需要访问列表中的当前项和下一项,但我想知道是否会遇到这样的情况,例如,我可能需要提前查看下一个“n”项。
发布于 2011-06-28 22:35:12
假设您使用的是.NET 4,那么您可以使用Zip来完成相同的任务:
var query = original.Zip(original.Skip(1),
(current, next) => new { current, next });这将对序列进行两次迭代。一个比你当前的扩展方法更好的替代方法(顺便说一句,我不相信它会起作用,因为IEnumerable没有Count属性,而且你也试图把theList作为一个方法来调用……)应该是这样的:
public static void Visit<TItem>(this IEnumerable<TItem> theList,
Action<TItem, TItem> visitor)
{
TItem prev = default(TItem);
using (var iterator = theList.GetEnumerator())
{
if (!iterator.MoveNext())
{
return;
}
prev = iterator.Current;
while (iterator.MoveNext())
{
TItem current = iterator.Current;
visitor(prev, current);
prev = current;
}
}
visitor(prev, default(TItem)); // Are you sure you want this?
}老实说,更通用的先行预测更棘手……你可能需要某种循环缓冲区,我猜...可能是一个自定义集合。
发布于 2014-03-07 23:10:10
当我们遇到类似的任务时,我们定义了一个扩展方法:
/// <summary>
/// Projects a window of source elements in a source sequence into target sequence.
/// Thus
/// target[i] =
/// selector(source[i], source[i - 1], ... source[i - window + 1])
/// </summary>
/// <typeparam name="T">A type of elements of source sequence.</typeparam>
/// <typeparam name="R">A type of elements of target sequence.</typeparam>
/// <param name="source">A source sequence.</param>
/// <param name="window">A size of window.</param>
/// <param name="lookbehind">
/// Indicate whether to produce target if the number of source elements
/// preceeding the current is less than the window size.
/// </param>
/// <param name="lookahead">
/// Indicate whether to produce target if the number of source elements
/// following current is less than the window size.
/// </param>
/// <param name="selector">
/// A selector that derives target element.
/// On input it receives:
/// an array of source elements stored in round-robing fashon;
/// an index of the first element;
/// a number of elements in the array to count.
/// </param>
/// <returns>Returns a sequence of target elements.</returns>
public static IEnumerable<R> Window<T, R>(
this IEnumerable<T> source,
int window,
bool lookbehind,
bool lookahead,
Func<T[], int, int, R> selector)
{
var buffer = new T[window];
var index = 0;
var count = 0;
foreach(var value in source)
{
if (count < window)
{
buffer[count++] = value;
if (lookbehind || (count == window))
{
yield return selector(buffer, 0, count);
}
}
else
{
buffer[index] = value;
index = index + 1 == window ? 0 : index + 1;
yield return selector(buffer, index, count);
}
}
if (lookahead)
{
while(--count > 0)
{
index = index + 1 == window ? 0 : index + 1;
yield return selector(buffer, index, count);
}
}
}
/// <summary>
/// Projects a window of source elements in a source sequence into a
/// sequence of window arrays.
/// </summary>
/// <typeparam name="T">A type of elements of source sequence.</typeparam>
/// <typeparam name="R">A type of elements of target sequence.</typeparam>
/// <param name="source">A source sequence.</param>
/// <param name="window">A size of window.</param>
/// <param name="lookbehind">
/// Indicate whether to produce target if the number of source elements
/// preceeding the current is less than the window size.
/// </param>
/// <param name="lookahead">
/// Indicate whether to produce target if the number of source elements
/// following current is less than the window size.
/// </param>
/// <returns>Returns a sequence of windows.</returns>
public static IEnumerable<T[]> Window<T>(
this IEnumerable<T> source,
int window,
bool lookbehind,
bool lookahead)
{
return source.Window(
window,
lookbehind,
lookahead,
(buffer, index, count) =>
{
var result = new T[count];
for(var i = 0; i < count; ++i)
{
result[i] = buffer[index];
index = index + 1 == buffer.Length ? 0 : index + 1;
}
return result;
});
}这些函数有助于从输入元素的窗口中生成输出元素。
另请参见LINQ extensions。
发布于 2011-06-28 22:32:37
您似乎使用了错误的类型。对序列进行索引的操作将对其进行迭代,直到它每次都达到指定的索引。为什么不使用IList<T>或ReadOnlyCollection<T>
https://stackoverflow.com/questions/6508060
复制相似问题