C# Linq前瞻迭代
我正在使用访问者类型模式遍历集合,需要访问列表中的当前项和下一项。目前,我是通过这样一种扩展方法来实现的C# Linq前瞻迭代,c#,linq,iteration,C#,Linq,Iteration,我正在使用访问者类型模式遍历集合,需要访问列表中的当前项和下一项。目前,我是通过这样一种扩展方法来实现的 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) {
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));
}
}
}
公共无效访问(此IEnumerable列表,操作访问者)
{
对于(i=0;i而言,您似乎使用了错误的类型。为序列编制索引的行为每次都会对序列进行迭代,直到它达到指定的索引。为什么不使用IList
或ReadOnlyCollection
?假设您使用的是.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?
}
公共静态无效访问(此IEnumerable列表,
行动(访客)
{
TItem prev=默认值(TItem);
使用(var iterator=theList.GetEnumerator())
{
如果(!iterator.MoveNext())
{
返回;
}
prev=迭代器。当前;
while(iterator.MoveNext())
{
TItem current=迭代器.current;
访客(上一位、现任);
prev=当前值;
}
}
visitor(prev,default(TItem));//您确定要这样做吗?
}
老实说,更全面的前瞻更为棘手……我想,您可能需要某种循环缓冲区……可能是一个自定义集合。未经测试,但我认为这是可行的?当访问超出边界时,它会循环到列表的前面
public class FriendlyEnumerable<T> : IEnumerable<T>
{
private IEnumerable<T> _enum;
public FriendlyEnumerable(IEnumerable<T> enumerable)
{
_enum = enumerable;
}
public void VisitAll(Action<T, T> visitFunc)
{
VisitAll(visitFunc, 1);
}
public void VisitAll(Action<T, T> visitFunc, int lookahead)
{
int index = 0;
int length = _enum.Count();
_enum.ToList().ForEach(t =>
{
for (int i = 1; i <= lookahead; i++)
visitFunc(t, _enum.ElementAt((index + i) % length));
index++;
});
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return _enum.GetEnumerator();
}
#endregion
}
公共类友好可枚举:IEnumerable
{
私有IEnumerable _enum;
公共友好可枚举(IEnumerable enumerable)
{
_枚举=可枚举;
}
公共无效访问权限(操作访问权限)
{
VisitAll(visitFunc,1);
}
public void VisitAll(Action visitFunc,int lookahead)
{
int指数=0;
int length=_enum.Count();
_enum.ToList().ForEach(t=>
{
对于(int i=1;i
{
如果(s1==s2)
结果。添加(s1+“=”+s2);
});
fe.VisitAll(比较);
//没有结果
fe.VisitAll(比较,4);
//8结果
公共静态无效访问lookahead(
这是一个数不清的来源,
行动访客,
int targetSize
)
{
if(targetSize子列表.计数==targetSize);
if(foundList!=null)
{
集合。删除(foundList);
访客(发现名单);
}
}
//在末尾生成额外列表-当前瞻将丢失项目时。
foreach(可枚举范围中的int i(1,targetSize)
{
collections.ForEach(subList=>subList.Add(默认值(TItem));
List foundList=集合
.FirstOrDefault(subList=>subList.Count==targetSize);
if(foundList!=null)
{
集合。删除(foundList);
访客(发现名单);
}
}
}
当我们遇到类似的任务时,我们定义了一个扩展方法:
/// <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;
});
}
//
///将源序列中的源元素窗口投影到目标序列中。
///因此
///目标[i]=
///选择器(源[i]、源[i-1]、…源[i-window+1])
///
///源序列的一种元素类型。
///目标序列的一种元素类型。
///源序列。
///窗户大小。
///
///如果源元素的数量增加,则指示是否生成目标
///在电流之前小于窗口大小。
///
///
///如果源元素的数量增加,则指示是否生成目标
///以下电流小于窗口大小。
///
///
///派生目标元素的选择器。
///在收到输入时:
///一个源元素数组,存储在round robing fashon中;
///第一个元素的索引;
///数组中要计数的元素数。
///
///返回目标元素的序列。
公共静态IEnumerable窗口(
这是一个数不清的来源,
int窗口,
布尔回头看,
布尔,向前看,
Func选择器)
{
var buffer=新的T[窗口];
var指数=0;
var计数=0;
foreach(源中的var值)
{
如果(计数<窗口)
{
缓冲区[计数++]=值;
if(lookbehind | |(count==窗口))
{
收益率返回选择器(缓冲区,0,计数);
}
}
其他的
{
缓冲区[索引]=值;
索引=索引+1==窗口?0:索引+1;
收益率返回选择器(缓冲区、索引、计数);
}
}
如果(向前看)
{
而(--计数>0)
{
索引=索引+1==窗口?0:索引+1;
收益率返回选择器(缓冲区、索引、计数);
}
}
}
///
///将源序列中的源元素窗口投影到
///窗口数组的序列。
///
///源序列的一种元素类型。
///目标序列的一种元素类型。
///源序列。
///窗户大小。
///
///如果源元素的数量增加,则指示是否生成目标
///在电流之前小于窗口大小。
///
///
///如果源元素的数量增加,则指示是否生成目标
///以下电流小于窗口大小。
///
///返回一系列窗口。
公共静态IEnumerable窗口(
这是一个数不清的来源,
int窗口,
布尔回头看,
布尔(前瞻)
{
返回源.Window(
窗口,
回头看,
展望未来,
(缓冲区、索引、计数)=>
{
var结果=新的T[计数];
对于(变量i=0;i
这些函数有助于从输入元素窗口生成输出元素
另请参见。您的代码甚至无法编译。IEnumerable
上没有名为Count
的属性(有一个方法组)。@Jason-thx-我编写了
public static void VisitLookAhead<TItem>(
this IEnumerable<TItem> source,
Action<IEnumerable<TItem>> visitor,
int targetSize
)
{
if (targetSize <= 1)
{
throw new Exception("invalid targetSize for VisitLookAhead");
}
List<List<TItem>> collections = new List<List<TItem>>();
// after 6th iteration with targetSize 6
//1, 2, 3, 4, 5, 6 <-- foundlist
//2, 3, 4, 5, 6
//3, 4, 5, 6
//4, 5, 6
//5, 6
//6
foreach(TItem x in source)
{
collections.Add(new List<TItem>());
collections.ForEach(subList => subList.Add(x));
List<TItem> foundList = collections
.FirstOrDefault(subList => subList.Count == targetSize);
if (foundList != null)
{
collections.Remove(foundList);
visitor(foundList);
}
}
//generate extra lists at the end - when lookahead will be missing items.
foreach(int i in Enumerable.Range(1, targetSize)
{
collections.ForEach(subList => subList.Add(default(TItem)));
List<TItem> foundList = collections
.FirstOrDefault(subList => subList.Count == targetSize);
if (foundList != null)
{
collections.Remove(foundList);
visitor(foundList);
}
}
}
/// <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;
});
}